diff --git a/admin-users/defaults/main.yml b/admin-users/defaults/main.yml deleted file mode 100644 index ad5f42cb..00000000 --- a/admin-users/defaults/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -admin_users: {} -admin_users_group: adm diff --git a/admin-users/tasks/admin_user.yml b/admin-users/tasks/admin_user.yml deleted file mode 100644 index 329ce50e..00000000 --- a/admin-users/tasks/admin_user.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- - -- include: user.yml - -- include: profile.yml - -- include: ssh.yml - -- include: sudo.yml - -- meta: flush_handlers diff --git a/admin-users/tasks/main.yml b/admin-users/tasks/main.yml deleted file mode 100644 index 6a1d1506..00000000 --- a/admin-users/tasks/main.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- - -- fail: - msg: only compatible with Debian >= 8 - when: - - ansible_distribution != "Debian" or ansible_distribution_major_version | version_compare('8', '<') - -- debug: - msg: "Warning: empty 'admin_users' variable, tasks will be skipped!" - when: admin_users == {} - -- include: admin_user.yml - vars: - user: "{{ item.value }}" - with_dict: "{{ admin_users }}" - when: admin_users != {} diff --git a/admin-users/tasks/profile.yml b/admin-users/tasks/profile.yml deleted file mode 100644 index 0101d4be..00000000 --- a/admin-users/tasks/profile.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- - -- name: is evomaintenance installed? - stat: - path: "/usr/share/scripts/evomaintenance.sh" - register: evomaintenance_script - check_mode: no - -- name: "Add evomaintenance trap for '{{ user.name }}'" - lineinfile: - state: present - dest: '/home/{{ user.name }}/.profile' - insertafter: EOF - line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0' - when: evomaintenance_script.stat.exists diff --git a/admin-users/tasks/sudo.yml b/admin-users/tasks/sudo.yml deleted file mode 100644 index e05ac614..00000000 --- a/admin-users/tasks/sudo.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- - -- name: "Verify Evolinux sudoers file presence (jessie)" - template: - src: sudoers_jessie.j2 - dest: /etc/sudoers.d/evolinux - force: no - validate: '/usr/sbin/visudo -cf %s' - register: copy_sudoers_evolinux - when: ansible_distribution_release == "jessie" - -- name: "Verify Evolinux sudoers file presence (Debian 9 or later)" - template: - src: sudoers_stretch.j2 - dest: /etc/sudoers.d/evolinux - force: no - validate: '/usr/sbin/visudo -cf %s' - register: copy_sudoers_evolinux - when: ansible_distribution_major_version | version_compare('9', '>=') - -- name: "Verify Evolinux sudoers file permissions" - file: - path: /etc/sudoers.d/evolinux - mode: "0440" - state: file - -- name: "Add user in sudoers file for '{{ user.name }}' (jessie)" - replace: - dest: /etc/sudoers.d/evolinux - regexp: '^(User_Alias\s+ADMINS\s+=((?!{{ user.name }}).)*)$' - replace: '\1,{{ user.name }}' - validate: '/usr/sbin/visudo -cf %s' - when: - - ansible_distribution_release == "jessie" - - not copy_sudoers_evolinux.changed - -- name: "Create evolinux-sudo group (Debian 9 or later)" - group: - name: evolinux-sudo - system: yes - when: ansible_distribution_major_version | version_compare('9', '>=') - -- name: "Add user to evolinux-sudo group (Debian 9 or later)" - user: - name: '{{ user.name }}' - groups: 'evolinux-sudo' - append: yes - when: ansible_distribution_major_version | version_compare('9', '>=') diff --git a/amavis/handlers/main.yml b/amavis/handlers/main.yml new file mode 100644 index 00000000..62049999 --- /dev/null +++ b/amavis/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart amavis + service: + name: amavis + state: restarted diff --git a/amavis/tasks/main.yml b/amavis/tasks/main.yml new file mode 100644 index 00000000..810ba505 --- /dev/null +++ b/amavis/tasks/main.yml @@ -0,0 +1,19 @@ +--- +- name: install Amavis + apt: + name: "{{ item }}" + state: present + with_items: + - postgrey + - amavisd-new + tags: + - amavis + +- name: configure Amavis + template: + src: amavis.conf.j2 + dest: /etc/amavis/conf.d/49-evolinux-defaults.conf + mode: "0644" + notify: restart amavis + tags: + - amavis diff --git a/amavis/templates/amavis.conf.j2 b/amavis/templates/amavis.conf.j2 new file mode 100644 index 00000000..cbe597a2 --- /dev/null +++ b/amavis/templates/amavis.conf.j2 @@ -0,0 +1,57 @@ +use strict; + +## Liste des domaines considérés comme locaux +#@local_domains_acl = qw(.); +@local_domains_acl = (".example.net","example.com"); + +# On customise la ligne ajoutée dans les entêtes +$X_HEADER_LINE = "by Amavis at $mydomain"; + +# On precise les FROM pour etre (bugs dans certaines version d'Amavis) +$mailfrom_notify_admin = "postmaster\@$mydomain"; +$mailfrom_notify_recip = "postmaster\@$mydomain"; +$mailfrom_notify_spamadmin = "postmaster\@$mydomain"; + +# Notifications de fichiers bannis / virus +$virus_admin = "postmaster\@$mydomain"; +# Ne pas recevoir des notifications pour les mails UNCHECKED +delete $admin_maps_by_ccat{&CC_UNCHECKED}; + +# Que faire avec les messages détectés +$final_virus_destiny = D_DISCARD; +$final_banned_destiny = D_BOUNCE; +$final_spam_destiny = D_BOUNCE; +$final_bad_header_destiny = D_PASS; + +# Pour recevoir des bounces (mails originals) des fichiers bloqués / virus +#$banned_quarantine_to = "banned\@$mydomain"; +#$virus_quarantine_to = "virus\@$mydomain"; + +# Note tueuse +$sa_tag2_level_deflt = 6.31; +# Pour un comportement "normal" de SA +$sa_tag_level_deflt = -1999; +$sa_kill_level_deflt = 1999; +$sa_dsn_cutoff_level = -99; +$sa_spam_subject_tag = '[SPAM]'; + +# log +$log_level = 2; + +# En fonction besoin/ressources, on a juste le nbre de process +$max_servers = 2; + +$enable_ldap = 1; +$default_ldap = { + hostname => '127.0.0.1', tls => 0, + base => '{{ ldap_suffix }}', scope => 'sub', + query_filter => '(&(mailacceptinggeneralid=%m)(isActive=TRUE))' +}; + +# Activer l'antivirus et antivirus +@bypass_virus_checks_maps = ( + \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); +@bypass_spam_checks_maps = ( + \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); + +1; # ensure a defined return diff --git a/amazon-ec2/README b/amazon-ec2/README new file mode 100644 index 00000000..15f8b129 --- /dev/null +++ b/amazon-ec2/README @@ -0,0 +1,60 @@ +# amazon-ec2 + +Manage Amazon EC2 instances. + +This role is intended to be called before any other role to setup and start EC2 +instances. + +## Dependencies + +You should first ensure that you have `python-boto` package installed on your +machine and an Amazon security access key pair created for your account. + +## Tasks + +By default, this role does nothing (no `main.yml` file). + +* `setup.yml`: create a security group and ssh keys +* `create-instance.yml`: create new EC2 instances +* `post-install.yml`: remove admin user created on Debian instances + +## Variables + + - `aws_access_key` and `aws_secret_key`: your AWS credentials + - `aws_region`: where to create instances. Default: ca-central-1 + - `ec2_public_ip`: assign public elastic IP address. Default: False + - `ec2_instance_count`: how many instance to launch. Default: 1 + - `ec2_security_group: EC2 security group to use. See + ec2_evolinux_security_group in `defaults/main.yml` to define your own. + Default: ec2_evolinux_security_group + - `ec2_base_ami`: EC2 image to use. Default is to use Debian official ones, + depending on the region + - `ec2_instance_type`: EC2 instance type to use + - `ssh_pubkey_file`: SSH public key file to push to AWS. Do not try to put + your ED25519 key here, AWS does not support it. Default: ~/.ssh/id_rsa.pub + - `ec2_keyname: a name to give to your public key on AWS. Default is to use + $USER environment variable. + +## Examples + +In your main evolinux playbook put this play before Evolinux one: + +``` +--- +- name: Prepare Amazon EC2 instance + hosts: localhost + gather_facts: False + + vars: + aws_access_key: + aws_secret_key: + # Any other variable you want to set. + + tasks: + - include_role: + name: amazon-ec2 + tasks_from: create-instance.yml +``` + +See amazon-ec2-evolinux.yml for an almost ready-to-use playbook to set up +Amazon EC2 instances running Evolinux. diff --git a/amazon-ec2/amazon-ec2-evolinux.yml b/amazon-ec2/amazon-ec2-evolinux.yml new file mode 100644 index 00000000..5c7a5e4e --- /dev/null +++ b/amazon-ec2/amazon-ec2-evolinux.yml @@ -0,0 +1,62 @@ +--- +- name: Prepare Amazon EC2 instance + hosts: localhost + gather_facts: False + + vars: + aws_access_key: + aws_secret_key: + aws_region: ca-central-1 + + tasks: + - include_role: + name: amazon-ec2 + tasks_from: setup.yml + - include_role: + name: amazon-ec2 + tasks_from: create-instance.yml + +- name: Install Evolinux + hosts: launched-instances + become: yes + + vars_files: + - 'vars/secrets.yml' + + vars: + admin_users: "{{ admin_users }}" + minifirewall_trusted_ips: "{{ trusted_ips }}" + fail2ban_ignore_ips: "{{ trusted_ips }}" + evolinux_hostname: + evolinux_domain: + evolinux_fqdn: + evolinux_internal_hostname: + minifirewall_public_ports_tcp: [80, 443] + minifirewall_public_ports_udp: [] + minifirewall_semipublic_ports_tcp: [22] + nagios_nrpe_allowed_hosts: "{{ trusted_ips }}" + + roles: + - etc-git + - evolinux-base + - admin-users + - munin + - minifirewall + - fail2ban + - nagios-nrpe + - listupgrade + - evomaintenance + - evocheck + - packweb-apache + - mysql + + post_tasks: + - include_role: + name: etc-git + tasks_from: commit.yml + vars: + commit_message: "Ansible post-run Evolinux playbook" + + - include_role: + name: evocheck + tasks_from: exec.yml diff --git a/amazon-ec2/defaults/main.yml b/amazon-ec2/defaults/main.yml new file mode 100644 index 00000000..c22b9df4 --- /dev/null +++ b/amazon-ec2/defaults/main.yml @@ -0,0 +1,135 @@ +--- +aws_region: ca-central-1 +ec2_public_ip: False +ec2_instance_count: 1 +ec2_security_group: "{{ ec2_evolinux_security_group }}" +ec2_base_ami: "{{ ec2_debian_base_ami[aws_region] }}" +ec2_instance_type: t2.micro +# Note: Do not try to put your ED25519 key here, AWS does not support it... +ssh_pubkey_file: ~/.ssh/id_rsa.pub +ec2_keyname: "{{ lookup('env', 'USER') }}" + +# From https://wiki.debian.org/Cloud/AmazonEC2Image/Stretch +ec2_debian_base_ami: + ap-northeast-1: ami-032dd665 + ap-northeast-2: ami-e174ac8f + ap-south-1: ami-6e7a3e01 + ap-southeast-1: ami-41365b22 + ap-southeast-2: ami-51f61333 + ca-central-1: ami-18239d7c + eu-central-1: ami-11bb0e7e + eu-west-1: ami-d037cda9 + eu-west-2: ami-ece3f388 + sa-east-1: ami-a24635ce + us-east-1: ami-ac5e55d7 + us-east-2: ami-9fbb98fa + us-west-1: ami-560c3836 + us-west-2: ami-fa18f282 + +ec2_evolinux_security_group: + name: evolinux-default + description: Evolinux default security group + rules: + - proto: icmp + cidr_ip: 0.0.0.0/0 + from_port: -1 + to_port: -1 + - proto: tcp + from_port: 22 + to_port: 22 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 5666 + to_port: 5666 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 53 + to_port: 53 + cidr_ip: 0.0.0.0/0 + - proto: udp + from_port: 53 + to_port: 53 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 389 + to_port: 389 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 636 + to_port: 636 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 143 + to_port: 143 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 993 + to_port: 993 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 110 + to_port: 110 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 995 + to_port: 995 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 25 + to_port: 25 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 80 + to_port: 80 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 443 + to_port: 443 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 21 + to_port: 21 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 20 + to_port: 20 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 5001 + to_port: 5001 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 465 + to_port: 465 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 587 + to_port: 587 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 8181 + to_port: 8181 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 8282 + to_port: 8282 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 9091 + to_port: 9091 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 2222 + to_port: 2222 + cidr_ip: 0.0.0.0/0 + - proto: tcp + from_port: 2223 + to_port: 2223 + cidr_ip: 0.0.0.0/0 + - proto: udp + from_port: 123 + to_port: 123 + cidr_ip: 0.0.0.0/0 + rules_egress: + - proto: all + cidr_ip: 0.0.0.0/0 diff --git a/amazon-ec2/tasks/create-instance.yml b/amazon-ec2/tasks/create-instance.yml new file mode 100644 index 00000000..470cac72 --- /dev/null +++ b/amazon-ec2/tasks/create-instance.yml @@ -0,0 +1,36 @@ +--- + +- name: Launch new instance(s) + ec2: + state: present + aws_access_key: "{{aws_access_key}}" + aws_secret_key: "{{aws_secret_key}}" + region: "{{aws_region}}" + image: "{{ec2_base_ami}}" + instance_type: "{{ec2_instance_type}}" + count: "{{ec2_instance_count}}" + assign_public_ip: "{{ec2_public_ip}}" + group: "{{ec2_security_group.name}}" + key_name: "{{ec2_keyname}}" + wait: yes + register: ec2 + +- name: Add newly created instance(s) to inventory + add_host: + hostname: "{{item.public_dns_name}}" + groupname: launched-instances + ansible_user: admin + ansible_ssh_common_args: "-o StrictHostKeyChecking=no" + with_items: "{{ec2.instances}}" + +- debug: + msg: "Your newly created instance is reachable at: {{item.public_dns_name}}" + with_items: "{{ec2.instances}}" + +- name: Wait for SSH to come up on all instances (give up after 2m) + wait_for: + state: started + host: "{{item.public_dns_name}}" + port: 22 + timeout: 120 + with_items: "{{ec2.instances}}" diff --git a/amazon-ec2/tasks/post-install.yml b/amazon-ec2/tasks/post-install.yml new file mode 100644 index 00000000..369f4941 --- /dev/null +++ b/amazon-ec2/tasks/post-install.yml @@ -0,0 +1,5 @@ +--- +- name: Remove admin user + user: + name: admin + state: absent diff --git a/amazon-ec2/tasks/setup.yml b/amazon-ec2/tasks/setup.yml new file mode 100644 index 00000000..27a1d8b0 --- /dev/null +++ b/amazon-ec2/tasks/setup.yml @@ -0,0 +1,20 @@ +--- +- name: Create default security group + ec2_group: + name: "{{ec2_security_group.name}}" + state: present + aws_access_key: "{{aws_access_key}}" + aws_secret_key: "{{aws_secret_key}}" + region: "{{aws_region}}" + description: "{{ec2_security_group.description}}" + rules: "{{ec2_security_group.rules}}" + +- name: Create key pair + ec2_key: + name: "{{ec2_keyname}}" + state: present + aws_access_key: "{{aws_access_key}}" + aws_secret_key: "{{aws_secret_key}}" + region: "{{aws_region}}" + key_material: "{{item}}" + with_file: "{{ssh_pubkey_file}}" diff --git a/apache/README.md b/apache/README.md index 66804981..40e17499 100644 --- a/apache/README.md +++ b/apache/README.md @@ -10,8 +10,8 @@ Everything is in the `tasks/main.yml` file for now. Main variables are : -* `apache_private_ipaddr_whitelist_present` : list of IP addresses to have in the private whitelist ; -* `apache_private_ipaddr_whitelist_absent` : list of IP addresses **not** to have in the whitelist; +* `apache_ipaddr_whitelist_present` : list of IP addresses to have in the private whitelist ; +* `apache_ipaddr_whitelist_absent` : list of IP addresses **not** to have in the whitelist; * `apache_private_htpasswd_present` : list of users to have in the private htpasswd ; * `apache_private_htpasswd_absent` : list of users to **not** have in the private htpasswd. * `log2mail_alert_email`: email address to send Log2mail messages to (default: `general_alert_email`). diff --git a/apache/defaults/main.yml b/apache/defaults/main.yml index 276f5a38..b21e1d59 100644 --- a/apache/defaults/main.yml +++ b/apache/defaults/main.yml @@ -1,6 +1,9 @@ --- -apache_private_ipaddr_whitelist_present: [] -apache_private_ipaddr_whitelist_absent: [] +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +apache_ipaddr_whitelist_present: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" +apache_ipaddr_whitelist_absent: [] apache_private_htpasswd_present: [] apache_private_htpasswd_absent: [] diff --git a/apache/files/private_ipaddr_whitelist.conf b/apache/files/ipaddr_whitelist.conf similarity index 100% rename from apache/files/private_ipaddr_whitelist.conf rename to apache/files/ipaddr_whitelist.conf diff --git a/apache/files/save_apache_status.sh b/apache/files/save_apache_status.sh new file mode 100644 index 00000000..d65b2e08 --- /dev/null +++ b/apache/files/save_apache_status.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +DIR="/var/log/apache-status" +URL="http://127.0.0.1/server-status" +TS=`date +%Y%m%d%H%M%S` +FILE="${DIR}/${TS}.html" + +mkdir -p "${DIR}" + +wget -q -O "${FILE}" "${URL}" + +chmod 640 "${FILE}" + +find "${DIR}" -type f -mtime +1 -delete + +exit 0 diff --git a/apache/tasks/auth.yml b/apache/tasks/auth.yml index 0f550a3c..dff100ce 100644 --- a/apache/tasks/auth.yml +++ b/apache/tasks/auth.yml @@ -2,7 +2,7 @@ - name: Init ipaddr_whitelist.conf file copy: - src: private_ipaddr_whitelist.conf + src: ipaddr_whitelist.conf dest: /etc/apache2/ipaddr_whitelist.conf owner: root group: root @@ -16,7 +16,7 @@ dest: /etc/apache2/ipaddr_whitelist.conf line: "Require ip {{ item }}" state: present - with_items: "{{ apache_private_ipaddr_whitelist_present }}" + with_items: "{{ apache_ipaddr_whitelist_present }}" notify: reload apache tags: - apache @@ -26,7 +26,7 @@ dest: /etc/apache2/ipaddr_whitelist.conf line: "Require ip {{ item }}" state: absent - with_items: "{{ apache_private_ipaddr_whitelist_absent }}" + with_items: "{{ apache_ipaddr_whitelist_absent }}" notify: reload apache tags: - apache diff --git a/apache/tasks/main.yml b/apache/tasks/main.yml index 50fb548a..3820fad2 100644 --- a/apache/tasks/main.yml +++ b/apache/tasks/main.yml @@ -38,6 +38,10 @@ - expires - headers - cgi + - ssl + - include + - negotiation + - alias notify: reload apache tags: - apache @@ -127,30 +131,17 @@ tags: - apache -- name: Stat /default index - stat: - path: /var/www/index.html - register: _default_index - check_mode: no +- include_role: + name: remount-usr tags: - apache -# - block: -# - name: generate random string for serverstatus suffix -# command: "apg -a 1 -M N -n 1" -# changed_when: False -# register: _random_serverstatus_suffix -# -# - name: overwrite apache_serverstatus_suffix -# set_fact: -# apache_serverstatus_suffix: "{{ _random_serverstatus_suffix.stdout }}" -# when: apache_serverstatus_suffix == "" -# -# - name: replace server-status suffix in default site index -# replace: -# dest: /var/www/index.html -# regexp: '__SERVERSTATUS_SUFFIX__' -# replace: "{{ apache_serverstatus_suffix }}" +- name: "Install save_apache_status.sh" + copy: + src: save_apache_status.sh + dest: /usr/share/scripts/save_apache_status.sh + mode: "0755" + force: no - include: log2mail.yml when: apache_log2mail_include diff --git a/apache/tasks/munin.yml b/apache/tasks/munin.yml index 85f0b386..9195ae0f 100644 --- a/apache/tasks/munin.yml +++ b/apache/tasks/munin.yml @@ -1,23 +1,55 @@ --- -- name: munin-node and core plugins are installed +- name: "Install munin-node and core plugins packages" apt: name: "{{ item }}" state: installed with_items: - munin-node - munin-plugins-core + tags: + - apache + - munin -- name: enable munin plugins +- name: "Enable Munin plugins" file: src: "/usr/share/munin/plugins/{{ item }}" dest: "/etc/munin/plugins/{{ item }}" state: link with_items: - - apache_accesses - - apache_processes - - apache_volume + - apache_accesses + - apache_processes + - apache_volume notify: restart munin-node tags: - - apache - - munin + - apache + - munin + +- name: "Install fcgi packages for Munin graphs" + apt: + name: "{{ item }}" + state: installed + with_items: + - libapache2-mod-fcgid + - libcgi-fast-perl + notify: reload apache + tags: + - apache + - munin + +- name: "Enable libapache2-mod-fcgid" + command: a2enmod fcgid + register: cmd_enable_fcgid + changed_when: "'Module fcgid already enabled' not in cmd_enable_fcgid.stdout" + notify: restart apache + tags: + - apache + - munin + +- name: "Apache has access to /var/log/munin/" + file: + path: /var/log/munin/ + group: www-data + tags: + - apache + - munin diff --git a/apache/templates/evolinux-default.conf.j2 b/apache/templates/evolinux-default.conf.j2 index b50409a8..238665b2 100644 --- a/apache/templates/evolinux-default.conf.j2 +++ b/apache/templates/evolinux-default.conf.j2 @@ -19,11 +19,13 @@ Require all denied Include /etc/apache2/ipaddr_whitelist.conf - - Options -Indexes + # munin-cgi-graph, used for zooming on graphs. + ScriptAlias /munin-cgi/munin-cgi-graph /usr/lib/munin/cgi/munin-cgi-graph + + Options +ExecCGI Require all denied Include /etc/apache2/ipaddr_whitelist.conf - + # For CGI Scripts. We need to set Directory directive as ScriptAlias take precedence. ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ diff --git a/apt/README.md b/apt/README.md index ec4da5b6..f3a8b13f 100644 --- a/apt/README.md +++ b/apt/README.md @@ -11,6 +11,7 @@ Tasks are extracted in several files, included in `tasks/main.yml` : ## Available variables +* `apt_config` : customize apt configuration (default: `True`) ; * `apt_install_basics` : change basic sources components (default: `True`) ; * `apt_basics_components` : basic sources components (default: `main`) ; * `apt_install_backports` : install backports sources (default: `False`) ; diff --git a/apt/defaults/main.yml b/apt/defaults/main.yml index 4e1cee3d..0960fd16 100644 --- a/apt/defaults/main.yml +++ b/apt/defaults/main.yml @@ -1,4 +1,10 @@ --- +apt_config: True +apt_evolinux_config: True +apt_hooks: True +apt_remove_aptitude: True +apt_upgrade: False + apt_install_basics: True apt_basics_components: "main" diff --git a/apt/handlers/main.yml b/apt/handlers/main.yml deleted file mode 100644 index e68f5c28..00000000 --- a/apt/handlers/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -- name: apt update - apt: - update_cache: yes diff --git a/apt/tasks/backports.yml b/apt/tasks/backports.yml index fd459a34..67b193d4 100644 --- a/apt/tasks/backports.yml +++ b/apt/tasks/backports.yml @@ -13,7 +13,7 @@ dest: /etc/apt/sources.list.d/backports.list force: yes mode: "0640" - notify: apt update + register: apt_backports_list tags: - apt @@ -23,11 +23,13 @@ dest: /etc/apt/preferences.d/0-backports-defaults force: yes mode: "0640" - notify: apt update + register: apt_backports_config tags: - apt -- name: Intermediate flush of handlers - meta: flush_handlers +- name: Apt update + apt: + update_cache: yes + when: apt_backports_list | changed or apt_backports_config | changed tags: - apt diff --git a/apt/tasks/basics.yml b/apt/tasks/basics.yml index d68e6063..f615c030 100644 --- a/apt/tasks/basics.yml +++ b/apt/tasks/basics.yml @@ -6,7 +6,7 @@ dest: /etc/apt/sources.list mode: "0644" force: yes - notify: apt update + register: apt_basic_list tags: - apt @@ -20,7 +20,9 @@ - /etc/apt/sources.list.d/debian-update.list when: apt_clean_gandi_sourceslist -- name: Intermediate flush of handlers - meta: flush_handlers +- name: Apt update + apt: + update_cache: yes + when: apt_basic_list | changed tags: - apt diff --git a/evolinux-base/tasks/apt.yml b/apt/tasks/config.yml similarity index 63% rename from evolinux-base/tasks/apt.yml rename to apt/tasks/config.yml index bb0be3fc..264e8dd7 100644 --- a/evolinux-base/tasks/apt.yml +++ b/apt/tasks/config.yml @@ -1,24 +1,19 @@ --- -- include_role: - name: apt - vars: - apt_install_basics: "{{ evolinux_apt_replace_default_sources }}" - apt_install_evolix_public: "{{ evolinux_apt_public_sources }}" - -- name: Setting apt config +- name: Evolinux config for APT lineinfile: dest: /etc/apt/apt.conf.d/z-evolinux.conf - line: "{{ item }}" + line: "{{ item.line }}" + regexp: "{{ item.regexp }}" create: yes state: present mode: "0640" with_items: - - "APT::Install-Recommends \"false\";" - - "APT::Install-Suggests \"false\";" - when: evolinux_apt_conf + - { line: "APT::Install-Recommends \"false\";", regexp: 'APT::Install-Recommends' } + - { line: "APT::Install-Suggests \"false\";", regexp: 'APT::Install-Suggests' } + when: apt_evolinux_config -- name: DPKg invoke hooks +- name: DPkg invoke hooks lineinfile: dest: /etc/apt/apt.conf.d/z-evolinux.conf line: "{{ item }}" @@ -30,13 +25,13 @@ - "DPkg::Pre-Invoke { \"df /usr | grep -q /usr && mount -oremount,rw /usr || true\"; };" - "DPkg::Post-Invoke { \"df /tmp | grep -q /tmp && mount -oremount /tmp || true\"; };" - "DPkg::Post-Invoke { \"df /usr | grep -q /usr && mount -oremount /usr || true\"; };" - when: evolinux_apt_hooks + when: apt_hooks - name: Remove Aptitude apt: name: aptitude state: absent - when: evolinux_apt_remove_aptitude + when: apt_remove_aptitude - name: Updating APT cache apt: @@ -46,6 +41,4 @@ - name: Upgrading system apt: upgrade: dist - when: evolinux_apt_upgrade - -- meta: flush_handlers + when: apt_upgrade diff --git a/apt/tasks/evolix_public.yml b/apt/tasks/evolix_public.yml index 5bfb3287..b1db38ab 100644 --- a/apt/tasks/evolix_public.yml +++ b/apt/tasks/evolix_public.yml @@ -19,11 +19,13 @@ dest: /etc/apt/sources.list.d/evolix_public.list force: yes mode: "0640" - notify: apt update + register: apt_evolix_public tags: - apt -- name: Intermediate flush of handlers - meta: flush_handlers +- name: Apt update + apt: + update_cache: yes + when: apt_evolix_public | changed tags: - apt diff --git a/apt/tasks/main.yml b/apt/tasks/main.yml index 7bb8950e..72960d02 100644 --- a/apt/tasks/main.yml +++ b/apt/tasks/main.yml @@ -7,6 +7,12 @@ tags: - apt +- name: Custom configuration + include: config.yml + when: apt_config + tags: + - apt + - name: Install basics repositories include: basics.yml when: apt_install_basics @@ -19,9 +25,6 @@ tags: - apt -- debug: - var: apt_install_evolix_public - - name: Install Evolix Public APT repository include: evolix_public.yml when: apt_install_evolix_public diff --git a/clamav/handlers/main.yml b/clamav/handlers/main.yml new file mode 100644 index 00000000..e053f01a --- /dev/null +++ b/clamav/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart clamav + service: + name: clamav-daemon + state: restarted diff --git a/clamav/meta/main.yml b/clamav/meta/main.yml new file mode 100644 index 00000000..510b6855 --- /dev/null +++ b/clamav/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: amavis } diff --git a/clamav/tasks/main.yml b/clamav/tasks/main.yml new file mode 100644 index 00000000..6e3058dd --- /dev/null +++ b/clamav/tasks/main.yml @@ -0,0 +1,111 @@ +--- +- name: configure clamav-daemon + debconf: + name: clamav-daemon + question: "{{ item.key }}" + value: "{{ item.value }}" + vtype: "{{ item.type }}" + with_items: + - { key: 'clamav-daemon/debconf', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/MaxHTMLNormalize', type: 'string', value: '10M' } + - { key: 'clamav-daemon/StatsPEDisabled', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/FollowDirectorySymlinks', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/StreamMaxLength', type: 'string', value: '25' } + - { key: 'clamav-daemon/ReadTimeout', type: 'string', value: '180' } + - { key: 'clamav-daemon/StatsEnabled', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/MaxConnectionQueueLength', type: 'string', value: '15' } + - { key: 'clamav-daemon/LogRotate', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/AllowAllMatchScan', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/ScanOnAccess', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/LogFile', type: 'string', value: '/var/log/clamav/clamav.log' } + - { key: 'clamav-daemon/ScanMail', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/BytecodeTimeout', type: 'string', value: '60000' } + - { key: 'clamav-daemon/LogTime', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/OnAccessMaxFileSize', type: 'string', value: '5M' } + - { key: 'clamav-daemon/TcpOrLocal', type: 'select', value: 'UNIX' } + - { key: 'clamav-daemon/MaxEmbeddedPE', type: 'string', value: '10M' } + - { key: 'clamav-daemon/FixStaleSocket', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/User', type: 'string', value: 'clamav' } + - { key: 'clamav-daemon/BytecodeSecurity', type: 'select', value: 'TrustSigned' } + - { key: 'clamav-daemon/ScanSWF', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/MaxDirectoryRecursion', type: 'string', value: '0' } + - { key: 'clamav-daemon/MaxThreads', type: 'string', value: '12' } + - { key: 'clamav-daemon/LocalSocketGroup', type: 'string', value: 'clamav' } + - { key: 'clamav-daemon/MaxScriptNormalize', type: 'string', value: '5M' } + - { key: 'clamav-daemon/ForceToDisk', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/StatsHostID', type: 'string', value: 'auto' } + - { key: 'clamav-daemon/FollowFileSymlinks', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/TCPSocket', type: 'string', value: '3310' } + - { key: 'clamav-daemon/TCPAddr', type: 'string', value: 'any' } + - { key: 'clamav-daemon/DisableCertCheck', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/SelfCheck', type: 'string', value: '3600' } + - { key: 'clamav-daemon/LocalSocket', type: 'string', value: '/var/run/clamav/clamd.ctl' } + - { key: 'clamav-daemon/LocalSocketMode', type: 'string', value: '666' } + - { key: 'clamav-daemon/StatsTimeout', type: 'string', value: '10' } + - { key: 'clamav-daemon/MaxZipTypeRcg', type: 'string', value: '1M' } + - { key: 'clamav-daemon/MaxHTMLNoTags', type: 'string', value: '2M' } + - { key: 'clamav-daemon/LogSyslog', type: 'boolean', value: 'false' } + - { key: 'clamav-daemon/AddGroups', type: 'string', value: '' } + - { key: 'clamav-daemon/Bytecode', type: 'boolean', value: 'true' } + - { key: 'clamav-daemon/ScanArchive', type: 'boolean', value: 'true' } + tags: + - clamav + +- name: configure clamav-freshclam + debconf: + name: clamav-freshclam + question: "{{ item.key }}" + value: "{{ item.value }}" + vtype: "{{ item.type }}" + with_items: + - { key: 'clamav-freshclam/autoupdate_freshclam', type: 'select', value: 'daemon' } + - { key: 'clamav-freshclam/proxy_user', type: 'string', value: '' } + - { key: 'clamav-freshclam/NotifyClamd', type: 'boolean', value: 'true' } + - { key: 'clamav-freshclam/local_mirror', type: 'select', value: 'db.fr.clamav.net' } + - { key: 'clamav-freshclam/http_proxy', type: 'string', value: '' } + - { key: 'clamav-freshclam/LogRotate', type: 'boolean', value: 'true' } + - { key: 'clamav-freshclam/Bytecode', type: 'boolean', value: 'true' } + - { key: 'clamav-freshclam/update_interval', type: 'string', value: '24' } + - { key: 'clamav-freshclam/SafeBrowsing', type: 'boolean', value: 'false' } + - { key: 'clamav-freshclam/PrivateMirror', type: 'string', value: '' } + - { key: 'clamav-freshclam/internet_interface', type: 'string', value: '' } + tags: + - clamav + +- name: install ClamAV + apt: + name: "{{ item }}" + state: present + with_items: + - clamav-daemon + - clamav + - clamdscan + - clamav-freshclam + - arc + - arj + - zoo + - pax + - bzip2 + - cabextract + - rpm + - lzop + - razor + tags: + - clamav + +- name: add clamav user to amavis group + user: + name: clamav + groups: amavis + append: True + tags: + - clamav + +- name: allow supplementary groups + replace: + dest: /etc/clamav/clamd.conf + regexp: 'AllowSupplementaryGroups false' + replace: 'AllowSupplementaryGroups true' + notify: restart clamav + tags: + - clamav diff --git a/dovecot/.kitchen.yml b/dovecot/.kitchen.yml new file mode 100644 index 00000000..687c2033 --- /dev/null +++ b/dovecot/.kitchen.yml @@ -0,0 +1,36 @@ +--- +driver: + name: docker + privileged: true + use_sudo: false + +provisioner: + name: ansible_playbook + hosts: test-kitchen + roles_path: ../ + ansible_verbose: true + require_ansible_source: false + require_chef_for_busser: false + idempotency_test: true + +platforms: + - name: debian + driver_config: + image: evolix/ansible:2.2.1 + +verifier: + name: serverspec + +suites: + - name: default + provisioner: + name: ansible_playbook + playbook: ./tests/test.yml + verifier: + patterns: + - nginx/tests/spec/memcached_spec.rb + bundler_path: '/usr/local/bin' + rspec_path: '/usr/local/bin' + +transport: + max_ssh_sessions: 6 diff --git a/dovecot/README.md b/dovecot/README.md new file mode 100644 index 00000000..736b95dc --- /dev/null +++ b/dovecot/README.md @@ -0,0 +1,11 @@ +# Dovecot + +Installation and basic configuration of dovecot + +## Tasks + +Minimal configuration is in `tasks/main.yml` + +## Available variables + +The full list of variables (with default values) can be found in `defaults/main.yml`. diff --git a/dovecot/defaults/main.yml b/dovecot/defaults/main.yml new file mode 100644 index 00000000..884bc1ca --- /dev/null +++ b/dovecot/defaults/main.yml @@ -0,0 +1,2 @@ +--- +dovecot_foo: bar diff --git a/dovecot/files/munin_plugin b/dovecot/files/munin_plugin new file mode 100755 index 00000000..e5a6d1d1 --- /dev/null +++ b/dovecot/files/munin_plugin @@ -0,0 +1,126 @@ +#! /bin/bash +# +# Munin Plugin +# to count logins to your dovecot mailserver +# +# Created by Dominik Schulz +# http://developer.gauner.org/munin/ +# Contributions by: +# - Stephane Enten +# - Steve Schnepp +# +# Parameters understood: +# +# config (required) +# autoconf (optional - used by munin-config) +# +# Config variables: +# +# logfile - Where to find the syslog file +# +# Add the following line to a file in /etc/munin/plugin-conf.d: +# env.logfile /var/log/your/logfile.log +# +# Magic markers (optional - used by munin-config and installation scripts): +# +#%# family=auto +#%# capabilities=autoconf + +###################### +# Configuration +###################### +EXPR_BIN=/usr/bin/expr +LOGFILE=${logfile:-/var/log/mail.log} +###################### + +if [ "$1" = "autoconf" ]; then + echo yes + exit 0 +fi + +if [ "$1" = "config" ]; then + echo 'graph_title Dovecot Logins' + echo 'graph_category Mail' + echo 'graph_args --base 1000 -l 0' + echo 'graph_vlabel Login Counters' + + for t in Total TLS SSL IMAP POP3 + do + field=$(echo $t | tr '[:upper:]' '[:lower:]') + echo "login_$field.label $t Logins" + echo "login_$field.type DERIVE" + echo "login_$field.min 0" + done + + echo 'connected.label Connected Users' + + exit 0 +fi + +###################### +# Total Logins +###################### +echo -en "login_total.value " +VALUE=$(egrep -c '[dovecot]?.*Login' $LOGFILE) +if [ ! -z "$VALUE" ]; then + echo "$VALUE" +else + echo "0" +fi +echo -n +###################### +# Connected Users +###################### +DISCONNECTS=$(egrep -c '[dovecot]?.*Disconnected' $LOGFILE) +CONNECTS=$(egrep -c '[dovecot]?.*Login' $LOGFILE) +VALUE=$($EXPR_BIN $CONNECTS - $DISCONNECTS) +if [ -z "$VALUE" ] || [ "$VALUE" -lt 0 ]; then + VALUE=0 +fi +echo -en "connected.value " +echo $VALUE +echo -n +###################### +# TLS Logins +###################### +echo -en "login_tls.value " +VALUE=$(egrep -c '[dovecot]?.*Login.*TLS' $LOGFILE) +if [ ! -z "$VALUE" ]; then + echo "$VALUE" +else + echo "0" +fi +echo -n +###################### +# SSL Logins +###################### +echo -en "login_ssl.value " +VALUE=$(egrep -c '[dovecot]?.*Login.*SSL' $LOGFILE) +if [ ! -z "$VALUE" ]; then + echo "$VALUE" +else + echo "0" +fi +echo -n +###################### +# IMAP Logins +###################### +echo -en "login_imap.value " +VALUE=$(egrep -c '[dovecot]?.*imap.*Login' $LOGFILE) +if [ ! -z "$VALUE" ]; then + echo "$VALUE" +else + echo "0" +fi +echo -n +###################### +# POP3 Logins +###################### +echo -en "login_pop3.value " +VALUE=$(egrep -c '[dovecot]?.*pop3.*Login' $LOGFILE) +if [ ! -z "$VALUE" ]; then + echo "$VALUE" +else + echo "0" +fi +echo -n diff --git a/dovecot/handlers/main.yml b/dovecot/handlers/main.yml new file mode 100644 index 00000000..8d1b78d8 --- /dev/null +++ b/dovecot/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: restart dovecot + service: + name: dovecot + state: restarted + +- name: reload dovecot + service: + name: dovecot + state: reloaded diff --git a/dovecot/tasks/main.yml b/dovecot/tasks/main.yml new file mode 100644 index 00000000..1a835160 --- /dev/null +++ b/dovecot/tasks/main.yml @@ -0,0 +1,68 @@ +- name: ensure packages are installed + apt: + name: '{{ item }}' + state: present + with_items: + - dovecot-ldap + - dovecot-imapd + - dovecot-pop3d + - dovecot-sieve + - dovecot-managesieved + tags: + - dovecot + +- name: disable pam auth + replace: + dest: /etc/dovecot/conf.d/10-auth.conf + regexp: "[^#]!include auth-system.conf.ext" + replace: "#!include auth-system.conf.ext" + tags: + - dovecot + +- name: update ldap auth + lineinfile: + dest: /etc/dovecot/dovecot-ldap.conf.ext + line: "{{ item.key }} = {{ item.value }}" + regexp: "^#*{{ item.key }}" + state: present + with_items: + - { key: 'hosts', value: '127.0.0.1' } + - { key: 'auth_bind', value: 'yes' } + - { key: 'ldap_version', value: 3 } + - { key: 'base', value: "{{ ldap_suffix }}" } + - { key: 'user_attrs', value: 'homeDirectory=home' } + - { key: 'user_filter', value: '(&(isActive=TRUE)(uid=%u))' } + - { key: 'pass_attrs', value: 'uid=user,userPassword=password' } + when: ldap_suffix is defined + notify: reload dovecot + tags: + - dovecot + +- name: create vmail group + group: + name: vmail + gid: 5000 + tags: + - dovecot + +- name: create vmail user + user: + name: vmail + group: vmail + uid: 5000 + shell: /bin/false + tags: + - dovecot + +- name: deploy evolix config + template: + src: z-evolinux-defaults.conf.j2 + dest: /etc/dovecot/conf.d/z-evolinux-defaults.conf + mode: "0644" + notify: reload dovecot + tags: + - dovecot + +- include: munin.yml + tags: + - dovecot diff --git a/dovecot/tasks/munin.yml b/dovecot/tasks/munin.yml new file mode 100644 index 00000000..7f5003f0 --- /dev/null +++ b/dovecot/tasks/munin.yml @@ -0,0 +1,20 @@ +--- + +- name: is Munin present ? + stat: + path: /etc/munin/plugin-conf.d/munin-node + check_mode: no + register: munin_node_plugins_config + +- block: + - name: Install munin plugin + copy: + src: munin_plugin + dest: /etc/munin/plugins/dovecot + mode: "0755" + +# TODO : add in /etc/munin/plugin-conf.d/munin-node +# [dovecot] +# group adm + + when: munin_node_plugins_config.stat.exists diff --git a/dovecot/templates/z-evolinux-defaults.conf.j2 b/dovecot/templates/z-evolinux-defaults.conf.j2 new file mode 100644 index 00000000..b6d8d5e5 --- /dev/null +++ b/dovecot/templates/z-evolinux-defaults.conf.j2 @@ -0,0 +1,36 @@ +# {{ ansible_managed }} + +# Autorise les mécanismes PLAIN/LOGIN même sans SSL/TLS +disable_plaintext_auth = no +auth_mechanisms = plain login + +# Authentification LDAP + intégration avec Postfix pour l'auth SMTP +!include auth-ldap.conf.ext +service auth { + unix_listener auth-userdb { + mode = 0600 + user = vmail + group = vmail + } + unix_listener /var/spool/postfix/private/auth-client { + mode = 0666 + user = postfix + group = postfix + } +} + +# Stockage des emails dans /home/mail avec UID/GID 5000/5000 +mail_location = maildir:/home/vmail/%d/%n +mail_uid = 5000 +mail_gid = 5000 + +# Activation Sieve +protocol lda { + mail_plugins = sieve +} + +# Optimisations +service login { + process_limit = 256 +} +mail_max_userip_connections = 42 diff --git a/drbd/README.md b/drbd/README.md index 86ae3aa6..f08d30f4 100644 --- a/drbd/README.md +++ b/drbd/README.md @@ -5,23 +5,3 @@ Install tools to setup DRBD replication accross servers. ## Tasks Everything is in the `tasks/main.yml` file. - -## Available variables - -The variable `admin_users` must be a "dict" of one or more users : - -``` -admin_users: - foo: - name: foo - uid: 1001 - fullname: 'Mr Foo' - password_hash: 'sdfgsdfgsdfgsdfg' - ssh_key: 'ssh-rsa AZERTYXYZ' - bar: - name: bar - uid: 1002 - fullname: 'Mr Bar' - password_hash: 'gsdfgsdfgsdfgsdf' - ssh_key: 'ssh-rsa QWERTYUIOP' -``` diff --git a/drbd/tasks/nagios.yml b/drbd/tasks/nagios.yml index 5ce44d7c..91b06c57 100644 --- a/drbd/tasks/nagios.yml +++ b/drbd/tasks/nagios.yml @@ -8,23 +8,8 @@ tags: - drbd -- name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - register: usr_partition - check_mode: no - tags: - - drbd - -- name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 and nagios_plugins_dir.stat.exists +- include_role: + name: remount-usr tags: - drbd diff --git a/elasticsearch/defaults/main.yml b/elasticsearch/defaults/main.yml index 77e36070..5fce4ef6 100644 --- a/elasticsearch/defaults/main.yml +++ b/elasticsearch/defaults/main.yml @@ -8,6 +8,7 @@ elasticsearch_custom_tmpdir: Null elasticsearch_default_tmpdir: /var/lib/elasticsearch/tmp elasticsearch_jvm_xms: 2g elasticsearch_jvm_xmx: 2g +elasticsearch_log_rotate_days: 365 elasticsearch_curator: False diff --git a/elasticsearch/meta/main.yml b/elasticsearch/meta/main.yml index a2f662c3..54156392 100644 --- a/elasticsearch/meta/main.yml +++ b/elasticsearch/meta/main.yml @@ -13,6 +13,7 @@ galaxy_info: - name: Debian versions: - jessie + - stretch galaxy_tags: [] # List tags for your role here, one per line. A tag is @@ -23,4 +24,5 @@ galaxy_info: # NOTE: A tag is limited to a single word comprised of # alphanumeric characters. Maximum 20 tags per role. -dependencies: [] +dependencies: + - java8 diff --git a/elasticsearch/tasks/curator.yml b/elasticsearch/tasks/curator.yml index c1a10658..e2546c7a 100644 --- a/elasticsearch/tasks/curator.yml +++ b/elasticsearch/tasks/curator.yml @@ -3,6 +3,7 @@ - name: Curator sources list is available apt_repository: repo: "deb http://packages.elastic.co/curator/4/debian stable main" + filename: elastic update_cache: yes state: present tags: diff --git a/elasticsearch/tasks/datadir.yml b/elasticsearch/tasks/datadir.yml index a0b87ad5..38d2218a 100644 --- a/elasticsearch/tasks/datadir.yml +++ b/elasticsearch/tasks/datadir.yml @@ -7,16 +7,16 @@ register: elasticsearch_custom_datadir_test check_mode: no - - name: "read the real datadir" command: readlink -f /var/lib/elasticsearch changed_when: false register: elasticsearch_current_real_datadir_test check_mode: no - tags: - elasticsearch - when: elasticsearch_custom_datadir + when: + - elasticsearch_custom_datadir != '' + - elasticsearch_custom_datadir != None - block: - name: elasticsearch is stopped @@ -40,5 +40,9 @@ name: elasticsearch state: started tags: - - elasticsearch - when: elasticsearch_custom_datadir and elasticsearch_custom_datadir != elasticsearch_current_real_datadir_test.stdout and not elasticsearch_custom_datadir_test.stat.exists + - elasticsearch + when: + - elasticsearch_custom_datadir != '' + - elasticsearch_custom_datadir != None + - elasticsearch_custom_datadir != elasticsearch_current_real_datadir_test.stdout + - not elasticsearch_custom_datadir_test.stat.exists diff --git a/elasticsearch/tasks/logs.yml b/elasticsearch/tasks/logs.yml new file mode 100644 index 00000000..ee3d7680 --- /dev/null +++ b/elasticsearch/tasks/logs.yml @@ -0,0 +1,9 @@ +--- + +- name: "log rotation script" + template: + src: rotate_elasticsearch_logs.j2 + dest: /etc/cron.daily/rotate_elasticsearch_logs + owner: root + group: root + mode: "0750" diff --git a/elasticsearch/tasks/main.yml b/elasticsearch/tasks/main.yml index 00be05ed..bc43bebd 100644 --- a/elasticsearch/tasks/main.yml +++ b/elasticsearch/tasks/main.yml @@ -10,6 +10,8 @@ - include: tmpdir.yml +- include: logs.yml + - include: plugin_head.yml when: elasticsearch_plugin_head diff --git a/elasticsearch/tasks/packages.yml b/elasticsearch/tasks/packages.yml index 05d5bf46..ff395cb5 100644 --- a/elasticsearch/tasks/packages.yml +++ b/elasticsearch/tasks/packages.yml @@ -1,12 +1,5 @@ --- -- name: install java8 - include_role: - name: java8 - tags: - - elasticsearch - - packages - - name: APT https transport is enabled apt: name: apt-transport-https @@ -27,7 +20,7 @@ - name: Elastic sources list is available apt_repository: repo: "deb https://artifacts.elastic.co/packages/5.x/apt stable main" - filename: elastic.list + filename: elastic state: present update_cache: yes tags: diff --git a/elasticsearch/tasks/plugin_head.yml b/elasticsearch/tasks/plugin_head.yml index c309f185..29b2f1f7 100644 --- a/elasticsearch/tasks/plugin_head.yml +++ b/elasticsearch/tasks/plugin_head.yml @@ -11,7 +11,7 @@ - block: - name: Head repository is checked-out git: - repo: "git://github.com/mobz/elasticsearch-head.git" + repo: "https://github.com/mobz/elasticsearch-head.git" dest: "{{ elasticsearch_plugin_head_clone_dir }}" clone: yes tags: @@ -53,3 +53,21 @@ - restart elasticsearch tags: - elasticsearch + +- name: Install systemd unit + template: + src: elasticsearch-head.service.j2 + dest: /etc/systemd/system/elasticsearch-head.service + tags: + - elasticsearch + - systemd + +- name: Enable systemd unit + systemd: + name: elasticsearch-head + daemon_reload: yes + enabled: yes + state: started + tags: + - elasticsearch + - systemd diff --git a/elasticsearch/tasks/tmpdir.yml b/elasticsearch/tasks/tmpdir.yml index 380fb190..b6bd445a 100644 --- a/elasticsearch/tasks/tmpdir.yml +++ b/elasticsearch/tasks/tmpdir.yml @@ -28,4 +28,4 @@ - restart elasticsearch tags: - elasticsearch - when: elasticsearch_custom_tmpdir or fstab_tmp_noexec | success + when: (elasticsearch_custom_tmpdir != '' and elasticsearch_custom_tmpdir != None) or fstab_tmp_noexec | success diff --git a/elasticsearch/templates/elasticsearch-head.service.j2 b/elasticsearch/templates/elasticsearch-head.service.j2 new file mode 100644 index 00000000..4e409ed0 --- /dev/null +++ b/elasticsearch/templates/elasticsearch-head.service.j2 @@ -0,0 +1,14 @@ +[Service] +Type=simple +ExecStart=/usr/bin/npm run start +User={{ elasticsearch_plugin_head_owner }} +Group={{ elasticsearch_plugin_head_group }} +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=elasticsearch-head +Restart=always +WorkingDirectory={{ elasticsearch_plugin_head_clone_dir }} +Environment=NODE_ENV=production + +[Install] +WantedBy=multi-user.target diff --git a/elasticsearch/templates/rotate_elasticsearch_logs.j2 b/elasticsearch/templates/rotate_elasticsearch_logs.j2 new file mode 100644 index 00000000..14d2d31d --- /dev/null +++ b/elasticsearch/templates/rotate_elasticsearch_logs.j2 @@ -0,0 +1,9 @@ +#!/bin/sh +# {{ ansible_managed }} + +LOG_DIR=/var/log/elasticsearch +USER=elasticsearch +MAX_AGE={{ elasticsearch_log_rotate_days | mandatory }} + +find ${LOG_DIR} -type f -user ${USER} -name "*.log.????-??-??" -exec gzip --best {} \; +find ${LOG_DIR} -type f -user ${USER} -name "*.log.????-??-??.gz" -mtime +${MAX_AGE} -delete diff --git a/evoacme/defaults/main.yml b/evoacme/defaults/main.yml index 4194b5aa..3d0842bc 100644 --- a/evoacme/defaults/main.yml +++ b/evoacme/defaults/main.yml @@ -5,6 +5,7 @@ evoacme_dhparam_size: 2048 evoacme_acme_dir: /var/lib/letsencrypt evoacme_csr_dir: /etc/ssl/requests evoacme_crt_dir: /etc/letsencrypt +evoacme_hooks_dir: "{{ evoacme_crt_dir }}/hooks" evoacme_log_dir: /var/log/evoacme evoacme_ssl_minday: 30 evoacme_ssl_ct: 'FR' diff --git a/evoacme/files/certbot.cron b/evoacme/files/certbot.cron index a7c4eef2..a16bcf69 100755 --- a/evoacme/files/certbot.cron +++ b/evoacme/files/certbot.cron @@ -7,8 +7,8 @@ # [ -f /etc/default/evoacme ] && . /etc/default/evoacme -[ -z "${CRT_DIR}" ] && CRT_DIR='/etc/letsencrypt' +CRT_DIR="${CRT_DIR:-'/etc/letsencrypt'}" -find "${CRT_DIR}" -maxdepth 1 -mindepth 1 -type d ! -path "*accounts" -exec basename {} \; | while read vhost; do - evoacme "$vhost" -done +export QUIET=1 + +find "${CRT_DIR}" -maxdepth 1 -mindepth 1 -type d ! -path "*accounts" ! -path "*hooks" -printf "%f\n" | xargs -n1 evoacme diff --git a/evoacme/files/evoacme.sh b/evoacme/files/evoacme.sh index ffbf22ac..e35c97b9 100755 --- a/evoacme/files/evoacme.sh +++ b/evoacme/files/evoacme.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # evoacme is a shell script to manage Let's Encrypt certificate with # certbot tool but with a dedicated user (no-root) and from a csr @@ -7,78 +7,287 @@ # Licence: AGPLv3 # +set -e +set -u + usage() { - echo "Usage: $0 NAME" - echo "" - echo "NAME must be correspond to :" - echo "- a CSR in ${CSR_DIR}/NAME.csr" - echo "- a KEY in ${SSL_KEY_DIR}/NAME.key" - echo "" + cat </dev/null && service apache2 reload +log() { + if [ "${QUIET}" != "1" ]; then + echo "${PROGNAME}: $1" + fi +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} +error() { + >&2 echo "${PROGNAME}: $1" + [ "$1" = "invalid argument(s)" ] && >&2 usage + exit 1 } -mkconf_nginx() { - [ -f "/etc/nginx/ssl/${vhost}.conf" ] && sed -i "s~^ssl_certificate[^_].*$~ssl_certificate $CRT_DIR/${vhost}/live/fullchain.pem;~" "/etc/nginx/ssl/${vhost}.conf" - nginx -t 2>/dev/null && service nginx reload -} +sed_cert_path_for_apache() { + local vhost=$1 + local vhost_full_path="/etc/apache2/ssl/${vhost}.conf" + local cert_path=$2 -mkconf_haproxy() { - mkdir -p /etc/ssl/haproxy -m 700 - cat "$CRT_DIR/${vhost}/live/fullchain.pem" "$SSL_KEY_DIR/${vhost}.key" > "/etc/ssl/haproxy/${vhost}.pem" - [ -f "$DH_DIR/${vhost}.pem" ] && cat "$DH_DIR/${vhost}.pem" >> "/etc/ssl/haproxy/${vhost}.pem" - haproxy -c -f /etc/haproxy/haproxy.cfg >/dev/null && service haproxy reload + [ ! -r "${vhost_full_path}" ] && return 0 + + local search="^SSLCertificateFile.*$" + local replace="SSLCertificateFile ${cert_path}" + + if ! $(grep -qE "${search}" "${vhost_full_path}"); then + [ -w "${vhost_full_path}" ] || error "File ${vhost_full_path} is not writable" + + sed -i "s~^${search}~${replace}~" "${vhost_full_path}" + debug "Config in ${vhost_full_path} has been updated" + $(command -v apache2ctl) -t + fi +} +sed_cert_path_for_nginx() { + local vhost=$1 + local vhost_full_path="/etc/nginx/ssl/${vhost}.conf" + local cert_path=$2 + + [ ! -r "${vhost_full_path}" ] && return 0 + + local search="^ssl_certificate[^_].*$" + local replace="ssl_certificate ${cert_path};" + + if ! $(grep -qE "${search}" "${vhost_full_path}"); then + [ -w "${vhost_full_path}" ] || error "File ${vhost_full_path} is not writable" + + sed -i "s~${search}~${replace}~" "${vhost_full_path}" + debug "Config in ${vhost_full_path} has been updated" + $(command -v nginx) -t + fi +} +x509_verify() { + local file="$1" + [ -r "$file" ] || error "File ${file} not found" + "${OPENSSL_BIN}" x509 -noout -modulus -in "$file" >/dev/null +} +x509_enddate() { + local file="$1" + [ -r "$file" ] || error "File ${file} not found" + "${OPENSSL_BIN}" x509 -noout -enddate -in "$file" +} +csr_verify() { + local file="$1" + [ -r "$file" ] || error "File ${file} not found" + "${OPENSSL_BIN}" req -noout -modulus -in "$file" >/dev/null } main() { - [ -f /etc/default/evoacme ] && . /etc/default/evoacme - [ -z "${SSL_KEY_DIR}" ] && SSL_KEY_DIR='/etc/ssl/private' - [ -z "${CRT_DIR}" ] && CRT_DIR='/etc/letsencrypt' - [ -z "${CSR_DIR}" ] && CSR_DIR='/etc/ssl/requests' - [ -z "${SELF_SIGNED_DIR}" ] && SELF_SIGNED_DIR='/etc/ssl/self-signed' - [ -z "${DH_DIR}" ] && DH_DIR='/etc/ssl/dhparam' - [ -z "${LOG_DIR}" ] && LOG_DIR='/var/log/evoacme' - - [ "$#" -ne 1 ] && usage && exit 1 + # check arguments + [ "$#" -eq 1 ] || error "invalid argument(s)" - vhost=$(basename "$1" .conf) + [ "$1" = "-h" ] || [ "$1" = "--help" ] && usage && exit 0 - # Check master status for evoadmin-cluster - if [ -f "/home/${vhost}/state" ]; then - grep -q "STATE=master" "/home/${vhost}/state" || exit 0 - fi + mkdir -p "${ACME_DIR}" + chown acme: "${ACME_DIR}" + [ -w "${ACME_DIR}" ] || error "Directory ${ACME_DIR} is not writable" - SSL_EMAIL=$(grep emailAddress "${CRT_DIR}/openssl.cnf"|cut -d'=' -f2|xargs) - if [ -n "$SSL_EMAIL" ]; then - emailopt="-m $SSL_EMAIL" - else - emailopt="--register-unsafely-without-email" - fi - DATE=$(date "+%Y%m%d") - - if [ -h "$CRT_DIR/${vhost}/live" ]; then - crt_end_date=$(openssl x509 -noout -enddate -in "$CRT_DIR/${vhost}/live/cert.crt"|sed -e "s/.*=//") - date_crt=$(date -ud "$crt_end_date" +"%s") - date_today=$(date +'%s') - date_diff=$(((date_crt - date_today) / (60*60*24))) - [ "$date_diff" -ge "$SSL_MINDAY" ] && exit 0 - fi - rm -rf "$CRT_DIR/${vhost}/${DATE}" - mkdir -pm 755 "$CRT_DIR/${vhost}/${DATE}" - chown -R acme: "$CRT_DIR/${vhost}" - sudo -u acme certbot certonly --quiet --webroot --csr "$CSR_DIR/${vhost}.csr" --webroot-path "$ACME_DIR" -n --agree-tos --cert-path="$CRT_DIR/${vhost}/${DATE}/cert.crt" --fullchain-path="$CRT_DIR/${vhost}/${DATE}/fullchain.pem" --chain-path="$CRT_DIR/${vhost}/${DATE}/chain.pem" "$emailopt" --logs-dir "$LOG_DIR" 2>&1 | grep -v "certbot.crypto_util" - if [ -f "$CRT_DIR/${vhost}/${DATE}/fullchain.pem" ]; then - rm -f "$CRT_DIR/${vhost}/live" - ln -s "$CRT_DIR/${vhost}/${DATE}" "$CRT_DIR/${vhost}/live" - which apache2ctl >/dev/null && mkconf_apache - which nginx >/dev/null && mkconf_nginx - which haproxy >/dev/null && mkconf_haproxy - else - rmdir "$CRT_DIR/${vhost}/${DATE}" - fi + [ -d "${CSR_DIR}" ] || error "Directory ${CSR_DIR} is not found" + + mkdir -p "${CRT_DIR}" + chown acme: "${CRT_DIR}" + [ -w "${CRT_DIR}" ] || error "Directory ${CRT_DIR} is not writable" + + mkdir -p "${LOG_DIR}" + chown acme: "${LOG_DIR}" + [ -w "${LOG_DIR}" ] || error "Directory ${LOG_DIR} is not writable" + + mkdir -p "${HOOKS_DIR}" + chown acme: "${HOOKS_DIR}" + [ -d "${HOOKS_DIR}" ] || error "Directory ${HOOKS_DIR} is not found" + + readonly VHOST=$(basename "$1" .conf) + + # check for important programs + readonly OPENSSL_BIN=$(command -v openssl) || error "openssl command not installed" + readonly CERTBOT_BIN=$(command -v certbot) || error "certbot command not installed" + + # double check for directories + [ -d "${ACME_DIR}" ] || error "${ACME_DIR} is not a directory" + [ -d "${CSR_DIR}" ] || error "${CSR_DIR} is not a directory" + [ -d "${LOG_DIR}" ] || error "${LOG_DIR} is not a directory" + + #### CSR VALIDATION + + # verify .csr file + readonly CSR_FILE="${CSR_DIR}/${VHOST}.csr" + debug "Using CSR file: ${CSR_FILE}" + [ -f "${CSR_FILE}" ] || error "${CSR_FILE} absent" + [ -r "${CSR_FILE}" ] || error "${CSR_FILE} is not readable" + + csr_verify "${CSR_FILE}" || error "${CSR_FILE} is invalid" + + # Hook for evoadmin-web in cluster mode : check master status + local evoadmin_state_file="/home/${VHOST}/state" + [ -r "${evoadmin_state_file}" ] \ + && grep -q "STATE=slave" "${evoadmin_state_file}" \ + && debug "We are slave of this evoadmin cluster. Quit!" \ + && exit 0 + + #### INIT OR RENEW? + + readonly LIVE_DIR="${CRT_DIR}/${VHOST}/live" + readonly LIVE_CERT="${LIVE_DIR}/cert.crt" + readonly LIVE_FULLCHAIN="${LIVE_DIR}/fullchain.pem" + readonly LIVE_CHAIN="${LIVE_DIR}/chain.pem" + + # If live symlink already exists, it's not our first time... + if [ -h "${LIVE_DIR}" ]; then + # we have a live symlink + # let's see if there is a cert to renew + x509_verify "${LIVE_CERT}" || error "${LIVE_CERT} is invalid" + + # Verify if our certificate will expire + crt_end_date=$(x509_enddate "${LIVE_CERT}" | cut -d= -f2) + date_renew=$(date -ud "${crt_end_date} - ${SSL_MINDAY} days" +"%s") + date_today=$(date +'%s') + if [ "${date_today}" -lt "${date_renew}" ]; then + debug "Cert ${LIVE_CERT} expires at ${crt_end_date} => more than ${SSL_MINDAY} days: kthxbye." + exit 0 + fi + fi + + #### CERTIFICATE CREATION WITH CERTBOT + + local iteration=$(date "+%Y%m%d%H%M%S") + [ -n "${iteration}" ] || error "invalid iteration (${iteration})" + + readonly NEW_DIR="${CRT_DIR}/${VHOST}/${iteration}" + + [ -d "${NEW_DIR}" ] && error "${NEW_DIR} directory already exists, remove it manually." + mkdir -p "${NEW_DIR}" + chmod -R 0700 "${CRT_DIR}" + chown -R acme: "${CRT_DIR}" + debug "New cert will be created in ${NEW_DIR}" + + readonly NEW_CERT="${NEW_DIR}/cert.crt" + readonly NEW_FULLCHAIN="${NEW_DIR}/fullchain.pem" + readonly NEW_CHAIN="${NEW_DIR}/chain.pem" + + local CERTBOT_MODE="" + [ "${TEST}" = "1" ] && CERTBOT_MODE="${CERTBOT_MODE} --test-cert" + [ "${QUIET}" = "1" ] && CERTBOT_MODE="${CERTBOT_MODE} --quiet" + [ "${DRY_RUN}" = "1" ] && CERTBOT_MODE="${CERTBOT_MODE} --dry-run" + + local CERTBOT_REGISTRATION="--agree-tos" + if [ -n "${SSL_EMAIL}" ]; then + debug "Registering at certbot with ${SSL_EMAIL} as email" + CERTBOT_REGISTRATION="${CERTBOT_REGISTRATION} -m ${SSL_EMAIL}" + else + debug "Registering at certbot without email" + CERTBOT_REGISTRATION="${CERTBOT_REGISTRATION} --register-unsafely-without-email" + fi + + # Permissions checks for acme user + sudo -u acme test -r "${CSR_FILE}" || error "File ${CSR_FILE} is not readable by user 'acme'" + sudo -u acme test -w "${NEW_DIR}" || error "Directory ${NEW_DIR} is not writable by user 'acme'" + + # create a certificate with certbot + sudo -u acme \ + "${CERTBOT_BIN}" \ + certonly \ + ${CERTBOT_MODE} \ + ${CERTBOT_REGISTRATION} \ + --non-interactive \ + --webroot \ + --csr "${CSR_FILE}" \ + --webroot-path "${ACME_DIR}" \ + --cert-path "${NEW_CERT}" \ + --fullchain-path "${NEW_FULLCHAIN}" \ + --chain-path "${NEW_CHAIN}" \ + --logs-dir "$LOG_DIR" \ + 2>&1 \ + | grep -v "certbot.crypto_util" + + if [ "${DRY_RUN}" = "1" ]; then + debug "In dry-run mode, we stop here. Bye" + exit 0 + fi + + # verify if all is right + x509_verify "${NEW_CERT}" || error "${NEW_CERT} is invalid" + x509_verify "${NEW_FULLCHAIN}" || error "${NEW_FULLCHAIN} is invalid" + x509_verify "${NEW_CHAIN}" || error "${NEW_CHAIN} is invalid" + + log "New certificate available at ${NEW_CERT}" + + #### CERTIFICATE ACTIVATION + + # link dance + if [ -h "${LIVE_DIR}" ]; then + rm "${LIVE_DIR}" + debug "Remove ${LIVE_DIR} link" + fi + ln -s "${NEW_DIR}" "${LIVE_DIR}" + debug "Link ${NEW_DIR} to ${LIVE_DIR}" + # verify final path + x509_verify "${LIVE_CERT}" || error "${LIVE_CERT} is invalid" + + # update Apache + sed_cert_path_for_apache "${VHOST}" "${LIVE_FULLCHAIN}" + # update Nginx + sed_cert_path_for_nginx "${VHOST}" "${LIVE_FULLCHAIN}" + + #### EXECUTE HOOKS + # + # executable scripts placed in ${HOOKS_DIR} + # are executed, unless their name ends with ".disabled" + + export EVOACME_VHOST_NAME="${VHOST}" + export EVOACME_CERT="${LIVE_CERT}" + export EVOACME_CHAIN="${LIVE_CHAIN}" + export EVOACME_FULLCHAIN="${LIVE_FULLCHAIN}" + + # search for files in hooks directory + for hook in $(find ${HOOKS_DIR} -type f); do + # keep only executables files, not containing a "." + if [ -x "${hook}" ] && (basename "${hook}" | grep -vqF "."); then + debug "Executing ${hook}" + ${hook} + fi + done } -main "$@" +readonly PROGNAME=$(basename "$0") +readonly PROGDIR=$(realpath -m $(dirname "$0")) +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} +readonly TEST=${TEST:-"0"} +readonly DRY_RUN=${DRY_RUN:-"0"} + +# Read configuration file, if it exists +[ -r /etc/default/evoacme ] && . /etc/default/evoacme + +# Default value for main variables +readonly SSL_KEY_DIR=${SSL_KEY_DIR:-"/etc/ssl/private"} +readonly ACME_DIR=${ACME_DIR:-"/var/lib/letsencrypt"} +readonly CSR_DIR=${CSR_DIR:-"/etc/ssl/requests"} +readonly CRT_DIR=${CRT_DIR:-"/etc/letsencrypt"} +readonly LOG_DIR=${LOG_DIR:-"/var/log/evoacme"} +readonly HOOKS_DIR=${HOOKS_DIR:-"${CRT_DIR}/hooks"} +readonly SSL_MINDAY=${SSL_MINDAY:-"30"} +readonly SSL_EMAIL=${SSL_EMAIL:-""} + +main ${ARGS} diff --git a/evoacme/files/hooks/reload_apache b/evoacme/files/hooks/reload_apache new file mode 100755 index 00000000..2cceb972 --- /dev/null +++ b/evoacme/files/hooks/reload_apache @@ -0,0 +1,28 @@ +#!/bin/sh + +readonly PROGNAME=$(basename "$0") +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} + +if [ -n "$(pidof apache2)" ]; then + if $($(command -v apache2ctl) -t 2> /dev/null); then + debug "Apache detected... reloading" + service apache2 reload + else + error " Apache config is broken, you must fix it !" + fi +else + debug "Apache is not running. Skip." +fi diff --git a/evoacme/files/hooks/reload_dovecot b/evoacme/files/hooks/reload_dovecot new file mode 100755 index 00000000..31da4fb4 --- /dev/null +++ b/evoacme/files/hooks/reload_dovecot @@ -0,0 +1,32 @@ +#!/bin/sh + +readonly PROGNAME=$(basename "$0") +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} + +if [ -n "$(pidof dovecot)" ]; then + if $($(command -v doveconf) > /dev/null); then + if $($(command -v doveconf)|grep -E "^ssl_cert[^_]"|grep -q "letsencrypt"); then + debug "Dovecot detected... reloading" + service dovecot reload + else + debug "Dovecot doesn't use Let's Encrypt certificate. Skip." + fi + else + error "Dovecot config is broken, you must fix it !" + fi +else + debug "Dovecot is not running. Skip." +fi diff --git a/evoacme/files/hooks/reload_nginx b/evoacme/files/hooks/reload_nginx new file mode 100755 index 00000000..35db3787 --- /dev/null +++ b/evoacme/files/hooks/reload_nginx @@ -0,0 +1,28 @@ +#!/bin/sh + +readonly PROGNAME=$(basename "$0") +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} + +if [ -n "$(pidof nginx)" ]; then + if $($(command -v nginx) -t 2> /dev/null); then + debug "Nginx detected... reloading" + service nginx reload + else + error "Nginx config is broken, you must fix it !" + fi +else + debug "Nginx is not running. Skip." +fi diff --git a/evoacme/files/hooks/reload_postfix b/evoacme/files/hooks/reload_postfix new file mode 100755 index 00000000..50ee20ce --- /dev/null +++ b/evoacme/files/hooks/reload_postfix @@ -0,0 +1,32 @@ +#!/bin/sh + +readonly PROGNAME=$(basename "$0") +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly QUIET=${QUIET:-"0"} + +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} +debug() { + if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then + >&2 echo "${PROGNAME}: $1" + fi +} + +if [ -n "$(pidof master)" ]; then + if $($(command -v postconf) > /dev/null); then + if $($(command -v postconf)|grep -E "^smtpd_tls_cert_file"|grep -q "letsencrypt"); then + debug "Postfix detected... reloading" + service postfix reload + else + debug "Postfix doesn't use Let's Encrypt certificate. Skip." + fi + else + error "Postfix config is broken, you must fix it !" + fi +else + debug "Postfix is not running. Skip." +fi diff --git a/evoacme/files/make-csr.sh b/evoacme/files/make-csr.sh index 844847ab..10c0f8e9 100755 --- a/evoacme/files/make-csr.sh +++ b/evoacme/files/make-csr.sh @@ -1,151 +1,248 @@ -#!/bin/sh +#!/bin/bash # -# make-csr is a shell script designed to automatically generate a +# make-csr is a shell script designed to automatically generate a # certificate signing request (CSR) from an Apache or a Nginx vhost # # Author: Victor Laborie # Licence: AGPLv3 # -get_domains() { - echo "$vhostfile"|grep -q nginx - if [ "$?" -eq 0 ]; then - domains=$(grep -oE "^( )*[^#]+" "$vhostfile" |grep -oE "[^\$]server_name.*;$"|sed 's/server_name//'|tr -d ';'|sed 's/\s\{1,\}//'|sed 's/\s\{1,\}/\n/g'|sort|uniq) - fi - - echo "$vhostfile" |grep -q apache2 - if [ "$?" -eq 0 ]; then - domains=$(grep -oE "^( )*[^#]+" "$vhostfile" |grep -oE "(ServerName|ServerAlias).*"|sed 's/ServerName//'|sed 's/ServerAlias//'|sed 's/\s\{1,\}//'|sort|uniq) - fi - valid_domains="" - nb=0 - - echo "Valid(s) domain(s) in $vhost :" - for domain in $domains; do - real_ip=$(dig +short "$domain"|grep -oE "([0-9]+\.){3}[0-9]+") - for ip in $(echo "$SRV_IP"|xargs -n1); do - if [ "${ip}" = "${real_ip}" ]; then - valid_domains="$valid_domains $domain" - nb=$(( nb + 1 )) - echo "* $domain -> $real_ip" - fi - done - done - - if [ "$nb" -eq 0 ]; then - nb=$(echo "$domains"|wc -l) - echo "* No valid domain found" - echo "All following(s) domain(s) will be used for CSR creation :" - for domain in $domains; do - echo "* $domain" - done - else - domains="$valid_domains" - fi - domains=$(echo "$domains"|xargs -n1) +set -u + +usage() { + cat <&2 echo "${PROGNAME}: $1" + fi +} +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} + +default_key_size() { + grep default_bits "${SSL_CONFIG_FILE}" | cut -d'=' -f2 | xargs +} + +sed_selfsigned_cert_path_for_apache() { + local apache_ssl_vhost_path="$1" + + mkdir -p $(dirname "${apache_ssl_vhost_path}") + if [ ! -f "${apache_ssl_vhost_path}" ]; then + cat > "${apache_ssl_vhost_path}" < "${nginx_ssl_vhost_path}" < /dev/null + + [ -r "${crt}" ] || error "Something went wrong, ${crt} has not been generated" +} +openssl_key(){ + local key="$1" + local key_dir=$(dirname "${key}") + local size="$2" + + [ -w "${key_dir}" ] || error "Directory ${key_dir} is not writable" + + "${OPENSSL_BIN}" genrsa -out "${key}" "${size}" 2> /dev/null + + [ -r "${key}" ] || error "Something went wrong, ${key} has not been generated" +} +openssl_csr() { + local csr="$1" + local csr_dir=$(dirname "${csr}") + local key="$2" + local cfg="$3" + + [ -w "${csr_dir}" ] || error "Directory ${csr_dir} is not writable" + + if $(grep -q "DNS:" "${cfg}"); then + # CSR with SAN + "${OPENSSL_BIN}" req -new -sha256 -key "${key}" -reqexts SAN -config "${cfg}" -out "${csr}" + else + # Single domain CSR + "${OPENSSL_BIN}" req -new -sha256 -key "${key}" -config "${cfg}" -out "${csr}" + fi + + [ -r "${csr}" ] || error "Something went wrong, ${csr} has not been generated" } make_key() { - openssl genrsa -out "$SSL_KEY_DIR/${vhost}.key" "$SSL_KEY_SIZE" 2>/dev/null - chown root: "$SSL_KEY_DIR/${vhost}.key" - chmod 600 "$SSL_KEY_DIR/${vhost}.key" + local key="$1" + local size="$2" + + openssl_key "${key}" "${size}" + debug "Private key stored at ${key}" + + chown root: "${key}" + chmod 600 "${key}" } make_csr() { - domains="$1" - nb=$(echo "$domains"|wc -l) - config_file="/tmp/make-csr-${vhost}.conf" + local domains=$@ + local nb=$# + local config_file="/tmp/make-csr-${VHOST}.conf" + local san="" - mkdir -p "$CSR_DIR" -m 0755 - - if [ "$nb" -eq 1 ]; then - cat /etc/letsencrypt/openssl.cnf - > "$config_file" < "${config_file}" < "$config_file" < "${config_file}" < "$CSR_DIR/${vhost}.csr" - fi - - if [ -f "$CSR_DIR/${vhost}.csr" ]; then - chmod 644 "$CSR_DIR/${vhost}.csr" - mkdir -p "$SELF_SIGNED_DIR" -m 0755 - openssl x509 -req -sha256 -days 365 -in "$CSR_DIR/${vhost}.csr" -signkey "$SSL_KEY_DIR/${vhost}.key" -out "$SELF_SIGNED_DIR/${vhost}.pem" - [ -f "$SELF_SIGNED_DIR/${vhost}.pem" ] && chmod 644 "$SELF_SIGNED_DIR/${vhost}.pem" - fi -} + fi + openssl_csr "${CSR_FILE}" "${SSL_KEY_FILE}" "${config_file}" + debug "CSR stored at ${CSR_FILE}" -mkconf_apache() { - mkdir -p /etc/apache2/ssl - if [ ! -f "/etc/apache2/ssl/${vhost}.conf" ]; then - cat > "/etc/apache2/ssl/${vhost}.conf" < "/etc/nginx/ssl/${vhost}.conf" <&2 - exit 1 - fi - vhost=$(basename "$1" .conf) - local_ip=$(ip a|grep brd|cut -d'/' -f1|grep -oE "([0-9]+\.){3}[0-9]+") + if [ -t 0 ]; then + # We have STDIN, so we should have at least 2 arguments + if [ "$#" -lt 2 ]; then + >&2 echo "invalid arguments" + >&2 usage + exit 1 + fi + # read VHOST from first argument + VHOST="$1" + # remove the first argument + shift + # read domains from remaining arguments + DOMAINS=$@ + else + # We don't have STDIN, so we should have only 1 argument + if [ "$#" != 1 ]; then + >&2 echo "invalid arguments" + >&2 usage + exit 1 + fi + # read VHOST from first argument + VHOST="$1" + # read domains from input + DOMAINS= + while read -r line ; do + DOMAINS="${DOMAINS} ${line}" + done + # trim the string to remove leading/trailing spaces + DOMAINS=$(echo "${DOMAINS}" | xargs) + fi + readonly VHOST + readonly DOMAINS - [ -f /etc/default/evoacme ] && . /etc/default/evoacme - [ -z "${SSL_KEY_DIR}" ] && SSL_KEY_DIR='/etc/ssl/private' - [ -z "${CSR_DIR}" ] && CSR_DIR='/etc/ssl/requests' - [ -z "${CRT_DIR}" ] && CRT_DIR='/etc/letsencrypt' - [ -z "${SELF_SIGNED_DIR}" ] && SELF_SIGNED_DIR='/etc/ssl/self-signed' - SSL_KEY_SIZE=$(grep default_bits /etc/letsencrypt/openssl.cnf|cut -d'=' -f2|xargs) - [ -n "${SRV_IP}" ] && SRV_IP="${SRV_IP} $local_ip" || SRV_IP="$local_ip" - - vhostfile=$(ls "/etc/nginx/sites-enabled/${vhost}" "/etc/nginx/sites-enabled/${vhost}.conf" "/etc/apache2/sites-enabled/${vhost}" "/etc/apache2/sites-enabled/${vhost}.conf" 2>/dev/null|head -n1) - - if [ ! -h "$vhostfile" ]; then - echo "$vhost is not a valid virtualhost !" >&2 - exit 1 - fi + mkdir -p "${CSR_DIR}" + chown root: "${CSR_DIR}" + [ -w "${CSR_DIR}" ] || error "Directory ${CSR_DIR} is not writable" - if [ -f "$SSL_KEY_DIR/${vhost}.key" ]; then - echo "$vhost key already exist, overwrite it ? (y)" - read REPLY - [ "$REPLY" = "Y" ] || [ "$REPLY" = "y" ] || exit 0 - rm -f "/etc/apache2/ssl/${vhost}.conf /etc/nginx/ssl/${vhost}.conf" - [ -h "${CRT_DIR}/${vhost}/live" ] && rm "${CRT_DIR}/${vhost}/live" - fi + mkdir -p "${SELF_SIGNED_DIR}" + chown root: "${SELF_SIGNED_DIR}" + [ -w "${SELF_SIGNED_DIR}" ] || error "Directory ${SELF_SIGNED_DIR} is not writable" - get_domains - make_key - make_csr "$domains" - which apache2ctl >/dev/null && mkconf_apache - which nginx >/dev/null && mkconf_nginx + mkdir -p "${SSL_KEY_DIR}" + chown root: "${SSL_KEY_DIR}" + [ -w "${SSL_KEY_DIR}" ] || error "Directory ${SSL_KEY_DIR} is not writable" + + [ -r "${SSL_CONFIG_FILE}" ] || error "File ${SSL_CONFIG_FILE} is not readable" + + # check for important programs + readonly OPENSSL_BIN=$(command -v openssl) || error "openssl command not installed" + + readonly SELF_SIGNED_FILE="${SELF_SIGNED_DIR}/${VHOST}.pem" + readonly SSL_KEY_FILE="${SSL_KEY_DIR}/${VHOST}.key" + readonly CSR_FILE="${CSR_DIR}/${VHOST}.csr" + + make_key "${SSL_KEY_FILE}" "${SSL_KEY_SIZE}" + make_csr ${DOMAINS} + + command -v apache2ctl >/dev/null && sed_selfsigned_cert_path_for_apache "/etc/apache2/ssl/${VHOST}.conf" + command -v nginx >/dev/null && sed_selfsigned_cert_path_for_nginx "/etc/nginx/ssl/${VHOST}.conf" } -main "$@" +readonly PROGNAME=$(basename "$0") +readonly PROGDIR=$(realpath -m $(dirname "$0")) +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} + +# Read configuration file, if it exists +[ -r /etc/default/evoacme ] && . /etc/default/evoacme + +# Default value for main variables +readonly CSR_DIR=${CSR_DIR:-'/etc/ssl/requests'} +readonly SSL_CONFIG_FILE=${SSL_CONFIG_FILE:-"/etc/letsencrypt/openssl.cnf"} +readonly SELF_SIGNED_DIR=${SELF_SIGNED_DIR:-'/etc/ssl/self-signed'} +readonly SSL_KEY_DIR=${SSL_KEY_DIR:-'/etc/ssl/private'} +readonly SSL_KEY_SIZE=${SSL_KEY_SIZE:-$(default_key_size)} + +main ${ARGS} diff --git a/evoacme/files/vhost-domains.sh b/evoacme/files/vhost-domains.sh new file mode 100755 index 00000000..fd25ce86 --- /dev/null +++ b/evoacme/files/vhost-domains.sh @@ -0,0 +1,153 @@ +#!/bin/bash +# +# make-csr is a shell script designed to automatically generate a +# certificate signing request (CSR) from an Apache or a Nginx vhost +# +# Author: Victor Laborie +# Licence: AGPLv3 +# + +set -u + +usage() { + cat <&2 echo "${PROGNAME}: $1" + fi +} +error() { + >&2 echo "${PROGNAME}: $1" + exit 1 +} + +real_ip_for_domain() { + dig +short "$1" | grep -oE "([0-9]+\.){3}[0-9]+" +} +local_ip() { + ip a | grep brd | cut -d'/' -f1 | grep -oE "([0-9]+\.){3}[0-9]+" +} + +nginx_domains() { + local vhost_file="$1" + + grep -oE "^( )*[^#]+" "${vhost_file}" \ + | grep -oE "[^\$]server_name.*;$" \ + | sed 's/server_name//' \ + | tr -d ';' \ + | sed 's/\s\{1,\}//' \ + | sed 's/\s\{1,\}/\n/g' \ + | sort \ + | uniq +} + +apache_domains() { + local vhost_file="$1" + + grep -oE "^( )*[^#]+" "${vhost_file}" \ + | grep -oE "(ServerName|ServerAlias).*" \ + | sed 's/ServerName//' \ + | sed 's/ServerAlias//' \ + | sed 's/\s\{1,\}//' \ + | sort \ + | uniq +} + +get_domains() { + local vhost_file="$1" + local ips="$2" + local domains="" + local valid_domains="" + local nb=0 + + if $(echo "${vhost_file}" | grep -q nginx); then + debug "Nginx vhost file used" + domains=$(nginx_domains "${vhost_file}") + fi + if $(echo "${vhost_file}" | grep -q apache2); then + debug "Apache vhost file used" + domains=$(apache_domains "${vhost_file}") + fi + + debug "Valid(s) domain(s) in ${vhost_file} :" + for domain in ${domains}; do + real_ip=$(real_ip_for_domain "${domain}") + for ip in $(echo "${ips}" | xargs -n1); do + if [ "${ip}" = "${real_ip}" ]; then + valid_domains="${valid_domains} ${domain}" + nb=$(( nb + 1 )) + debug "* ${domain} -> ${real_ip}" + fi + done + done + + if [ "${nb}" -eq 0 ]; then + nb=$(echo "${domains}" | wc -l) + debug "* No valid domain found" + debug "All following(s) domain(s) will be used for CSR creation :" + for domain in ${domains}; do + debug "* ${domain}" + done + else + domains="${valid_domains}" + fi + + echo "${domains}" | xargs -n 1 +} + +first_vhost_file_found() { + local vhost_name="$1" + + ls "/etc/nginx/sites-enabled/${vhost_name}" \ + "/etc/nginx/sites-enabled/${vhost_name}.conf" \ + "/etc/apache2/sites-enabled/${vhost_name}.conf" \ + 2>/dev/null \ + | head -n 1 +} + +main() { + if [ "$#" != 1 ]; then + >&2 usage + exit 1 + fi + if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + usage + exit 0 + fi + + local vhost_name=$(basename "$1" .conf) + local vhost_file=$(first_vhost_file_found "${vhost_name}") + + if [ ! -h "${vhost_file}" ]; then + >&2 echo "No virtualhost has been found for '${vhost_name}'." + exit 1 + fi + + local ips=$(local_ip) + if [ -n "${SRV_IP}" ]; then + ips="${ips} ${SRV_IP}" + fi + + get_domains "${vhost_file}" "${ips}" +} + +readonly PROGNAME=$(basename "$0") +readonly PROGDIR=$(realpath -m $(dirname "$0")) +readonly ARGS=$@ + +readonly VERBOSE=${VERBOSE:-"0"} +readonly SRV_IP=${SRV_IP:-""} + +main $ARGS diff --git a/evoacme/tasks/acme.yml b/evoacme/tasks/acme.yml index e28b3b12..16417ca6 100644 --- a/evoacme/tasks/acme.yml +++ b/evoacme/tasks/acme.yml @@ -22,6 +22,14 @@ group: acme state: directory +- name: "Fix hooks directory permissions" + file: + path: "{{ evoacme_hooks_dir }}" + mode: "0700" + owner: acme + group: acme + state: directory + - name: Fix log dir's right file: path: "{{ evoacme_log_dir }}" diff --git a/evoacme/tasks/certbot.yml b/evoacme/tasks/certbot.yml index 20658ec2..f01cc668 100644 --- a/evoacme/tasks/certbot.yml +++ b/evoacme/tasks/certbot.yml @@ -20,28 +20,26 @@ name: certbot state: latest -- name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - check_mode: no - - register: usr_partition - -- name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 +- include_role: + name: remount-usr - name: Remove certbot symlink for apt install file: path: /usr/local/bin/certbot state: absent +- name: stat /etc/cron.d/certbot + stat: + path: /etc/cron.d/certbot + register: etc_cron_d_certbot + +- name: Rename certbot dpkg cron to .disabled + copy: + remote_src: True + src: /etc/cron.d/certbot + dest: /etc/cron.d/certbot.disabled + when: etc_cron_d_certbot.stat.exists + - name: Remove certbot dpkg cron file: path: /etc/cron.d/certbot diff --git a/evoacme/tasks/conf.yml b/evoacme/tasks/conf.yml index b39b5384..4d9f6704 100644 --- a/evoacme/tasks/conf.yml +++ b/evoacme/tasks/conf.yml @@ -1,6 +1,6 @@ --- - ini_file: - dest: /etc/letsencrypt/openssl.cnf + dest: "{{ evoacme_crt_dir }}/openssl.cnf" section: 'req' option: "{{ item.name }}" value: "{{ item.var }}" diff --git a/evoacme/tasks/evoacme_hook.yml b/evoacme/tasks/evoacme_hook.yml new file mode 100644 index 00000000..200bcbc4 --- /dev/null +++ b/evoacme/tasks/evoacme_hook.yml @@ -0,0 +1,14 @@ +--- + +- name: "Search for {{ hook_name }} hook" + command: "find {{ evoacme_hooks_dir }} -type f \\( -name '{{ hook_name }}' -o -name '{{ hook_name }}.*' \\)" + check_mode: no + changed_when: False + register: _find_hook + +- name: "Copy {{ hook_name }} hook if missing" + copy: + src: "hooks/{{ hook_name }}" + dest: "{{ evoacme_hooks_dir }}/{{ hook_name }}" + mode: "0750" + when: _find_hook.stdout == "" diff --git a/evoacme/tasks/main.yml b/evoacme/tasks/main.yml index beac178e..08bb980a 100644 --- a/evoacme/tasks/main.yml +++ b/evoacme/tasks/main.yml @@ -9,11 +9,30 @@ - include: acme.yml +- include: evoacme_hook.yml + vars: + hook_name: "{{ item }}" + with_items: + - reload_apache + - reload_nginx + - reload_dovecot + - reload_postfix + - include: conf.yml - include: scripts.yml -- include: webserver.yml +- name: Determine Apache presence + stat: + path: /etc/apache2/apache2.conf + check_mode: no + register: sta + +- name: Determine Nginx presence + stat: + path: /etc/nginx/nginx.conf + check_mode: no + register: stn - include: apache.yml when: sta.stat.isreg is defined and sta.stat.isreg diff --git a/evoacme/tasks/scripts.yml b/evoacme/tasks/scripts.yml index 01e61fdb..77e7b75a 100644 --- a/evoacme/tasks/scripts.yml +++ b/evoacme/tasks/scripts.yml @@ -9,15 +9,23 @@ - name: Copy make-csr.sh script copy: - src: files/make-csr.sh + src: make-csr.sh dest: /usr/local/sbin/make-csr owner: root group: root mode: "0755" +- name: Copy vhost-domains.sh script + copy: + src: vhost-domains.sh + dest: /usr/local/sbin/vhost-domains + owner: root + group: root + mode: "0755" + - name: Copy evoacme script copy: - src: files/evoacme.sh + src: evoacme.sh dest: /usr/local/sbin/evoacme owner: root group: root diff --git a/evoacme/tasks/webserver.yml b/evoacme/tasks/webserver.yml deleted file mode 100644 index 8092aa98..00000000 --- a/evoacme/tasks/webserver.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -- name: Determine Nginx presence - stat: - path: /etc/nginx/nginx.conf - check_mode: no - register: stn - -- name: Determine Apache presence - stat: - path: /etc/apache2/apache2.conf - check_mode: no - register: sta diff --git a/evoacme/templates/nginx.conf.j2 b/evoacme/templates/nginx.conf.j2 index dbb8a769..378d37cb 100644 --- a/evoacme/templates/nginx.conf.j2 +++ b/evoacme/templates/nginx.conf.j2 @@ -1,5 +1,9 @@ location ~ /.well-known/acme-challenge { +{% if ansible_distribution_major_version > 8 %} + alias {{ evoacme_acme_dir }}/; +{% else %} alias {{ evoacme_acme_dir }}/.well-known/acme-challenge; +{% endif %} try_files $uri =404; allow all; } diff --git a/evocheck/tasks/install_local.yml b/evocheck/tasks/install_local.yml index d98ce0ae..7c0580c1 100644 --- a/evocheck/tasks/install_local.yml +++ b/evocheck/tasks/install_local.yml @@ -1,5 +1,6 @@ --- -- include: remount_usr_rw.yml +- include_role: + name: remount-usr when: evocheck_bin_dir | search ("/usr") - name: Scripts dir is present diff --git a/evocheck/tasks/remount_usr_rw.yml b/evocheck/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/evocheck/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/evolinux-base/README.md b/evolinux-base/README.md index 8ef7a70e..dbcf7762 100644 --- a/evolinux-base/README.md +++ b/evolinux-base/README.md @@ -36,6 +36,7 @@ Main variables are: * `evolinux_additional_packages`: optional additional packages to install (default: `[]`) * `evolinux_postfix_purge_exim`: purge Exim packages (default: `True`) ; * `evolinux_ssh_password_auth_addresses`: list of addresses that can authenticate with a password (default: `[]`) -* `evolinux_ssh_disable_root`: disable SSH access for root (default: `True`) +* `evolinux_ssh_disable_root`: disable SSH access for root (default: `False`) +* `evolinux_ssh_allow_current_user`: don't lock yourself out (default: `False`) The full list of variables (with default values) can be found in `defaults/main.yml`. diff --git a/evolinux-base/defaults/main.yml b/evolinux-base/defaults/main.yml index e0c91fd1..54e5d85c 100644 --- a/evolinux-base/defaults/main.yml +++ b/evolinux-base/defaults/main.yml @@ -10,6 +10,21 @@ logcheck_alert_email: Null raid_alert_email: Null postfix_alias_email: Null +# apt + +evolinux_apt_include: True + +evolinux_apt_conf: True +evolinux_apt_hooks: True +evolinux_apt_replace_default_sources: True +evolinux_apt_public_sources: True +evolinux_apt_upgrade: True +evolinux_apt_remove_aptitude: True + +# etc-git + +evolinux_etcgit_include: True + # hostname evolinux_hostname_include: True @@ -31,17 +46,6 @@ evolinux_kernel_disable_tcp_timestamps: True evolinux_kernel_reduce_swapiness: True evolinux_kernel_cve20165696: True -# apt - -evolinux_apt_include: True - -evolinux_apt_conf: True -evolinux_apt_hooks: True -evolinux_apt_replace_default_sources: True -evolinux_apt_public_sources: True -evolinux_apt_upgrade: True -evolinux_apt_remove_aptitude: True - # fstab evolinux_fstab_include: True @@ -96,6 +100,27 @@ evolinux_system_alert5_init: True evolinux_system_alert5_enable: True evolinux_system_eni_auto: True +# evomaintenance + +evolinux_evomaintenance_include: True + +# ssh + +evolinux_ssh_include: True + +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +evolinux_ssh_password_auth_addresses: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" +evolinux_ssh_match_address: True +evolinux_ssh_disable_acceptenv: True +evolinux_ssh_allow_current_user: False + +### disabled because of a memory leak +# # evolinux users +# +# evolinux_users_include: True + # root evolinux_root_include: True @@ -108,15 +133,7 @@ evolinux_root_gitconfig: True evolinux_root_bash_history_appendonly: True evolinux_root_vim_default: True evolinux_root_vim_conf: True - -# ssh - -evolinux_ssh_include: True - -evolinux_ssh_password_auth_addresses: [] -evolinux_ssh_match_address: True -evolinux_ssh_disable_root: True -evolinux_ssh_disable_acceptenv: True +evolinux_root_disable_ssh: False # postfix @@ -152,3 +169,31 @@ evolinux_hardware_include: True evolinux_provider_online_include: False evolinux_provider_orange_fce_include: False + +# log2mail + +evolinux_log2mail_include: True + +# Minifirewall + +evolinux_minifirewall_include: True + +# Munin + +evolinux_munin_include: True + +# Nagios/NRPE + +evolinux_nagios_nrpe_include: True + +# fail2ban + +evolinux_fail2ban_include: True + +# Listupgrade + +evolinux_listupgrade_include: True + +# Generate ldif + +evolinux_generateldif_include: True diff --git a/evolinux-base/files/alert5.service b/evolinux-base/files/alert5.service new file mode 100644 index 00000000..ea560a51 --- /dev/null +++ b/evolinux-base/files/alert5.service @@ -0,0 +1,9 @@ +[Unit] +Description=Evolix alert5 script + +[Service] +Type=oneshot +ExecStart=/usr/share/scripts/alert5.sh + +[Install] +WantedBy=multi-user.target diff --git a/evolinux-base/files/hwraid.le-vert.net.gpg.key b/evolinux-base/files/hwraid.le-vert.net.gpg.key new file mode 100644 index 00000000..6d2f49d3 --- /dev/null +++ b/evolinux-base/files/hwraid.le-vert.net.gpg.key @@ -0,0 +1,31 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.12 (GNU/Linux) + +mQENBFHwGLoBCADGXHFostxbz4UzGFYtmox4pvyN1gMhq2KCuQ6f+FESa4HTd9L6 +XVhXWPCad3cdxBIls+41+AdZTWxWMu7DUdy8nMU1Ikfw6JeHcSx97G5BdxBVMjK4 +iMGfPdLfDgWf4BQ2h0dnTEWobt31WaqgNiNjNrKktqbymmF94pwYkwL53ydIA4zl +8ZQRZooFigkS9WdoKjh30Pv/SWakILSLcSQFHK0dvSkeGd1NxT9dMNPAXXqLom4+ +7kCc0s04sS+0DwW16b0Hpb46mtsR9kzOnrE/Smj24uOGzNZen0oCc2Y7bfZlyaN+ +RlTkWEze7lemc4Byup/QWkhT0Er8F8uxexy5ABEBAAG0PEhXUmFpZCAoaHR0cDov +L2h3cmFpZC5sZS12ZXJ0Lm5ldCkgPHJvb3RAaHdyYWlkLmxlLXZlcnQubmV0PokB +OAQTAQIAIgUCUfAYugIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQYAUh +DiOz07Rc4Af+N3dEZZHzLNVTjQ0+fCyeg8/flWOkR8DhP10cyoJhSHFTZRdXVshn +kP4VmmUycVeURh76DmrIRe/9Oyca6aGXccRMqvq+HMgBPVwD5qNhcJPIuzqEvmlO +6UIeW2ydil/v1pWu740fGntyFRQcsfqjReVPXw9K588F7MDMyL+31vLm6aorLSzR +hvLhOmGisTs0wg2Oz9f4muauRy6cpQPw/Zi/P/F4WkQYscbHrSbhszj6OIg/vftR +UbZ7QB26/+40B0ag4JzLpmj3scFxf/WdUl5LXazqhsbkurk7huV41BNKXi1+BS3c +x6pFzWEHpiuG1j7U/nScGzEQpsMlUW9D+rkBDQRR8Bi6AQgAuhH1H0VLwcROI/5n +9yTxSbTIZbyhUan3raAbit3pgo0zLagfUtp3vULVnm5ISqQcYFGLZoE1MUkmjGOL +38W0lsIiZTaKOKXxBbLlPhhrvlXnNWAG/S1wnq7K+DV179KCTkUzaLRDbHvv999j +9odBRtAkiTnCfHTMCN4AhydEejNxtlzJo4E5FecH4reimLI5euUdTltgCjixrbsa +KbQftYpSMdXnLy2+00QZoXu0U/h4WZcMhOSEEiyGP9BY6m5G76n03HIeQ6eALDFu +ryAgO+SB9rBrm/VN0kR/TZq0iA3uzLHC7zCw2aImipkr+rIuJOku0wH9MyowBbia +bQtnCQARAQABiQEfBBgBAgAJBQJR8Bi6AhsMAAoJEGAFIQ4js9O0d5YH/3fNQgsC +LvD0g2wdoksv5bG9CUOi9Bs0JHqI0LhXmPvMsbDojZ+zZle7KWNfK2227mWhmoG1 +WLujJSmTtxhEO1fXIdYjlDfk2uLJKuFi2wQX9n8dFDUmKY3CUJgeVZof1uQ/5C3D +O06CcuOtf2d/+iijuW112aV1q1hoQqw71ojTET0iIV6lD/0i1eEBSSe1Ohb9yTGR +VxTVrB78zU9hih4/Oq8wJT/Fv25aO1MDSc26CXAg0JA6IWvKal3BSPNhtz4L4FIg +lXleArf9oJqxDO3TsV5zcLyxsIuRuxyP0+AKdSQUqv0dFi4Jf79OmvOmgwydhHjY ++f7quLbwiiDmPbU= +=Yv6D +-----END PGP PUBLIC KEY BLOCK----- diff --git a/evolinux-base/meta/main.yml b/evolinux-base/meta/main.yml index 2d640995..2b6aed3c 100644 --- a/evolinux-base/meta/main.yml +++ b/evolinux-base/meta/main.yml @@ -12,6 +12,7 @@ galaxy_info: - name: Debian versions: - jessie + - stretch dependencies: [] # List your role dependencies here, one per line. diff --git a/evolinux-base/tasks/fstab.yml b/evolinux-base/tasks/fstab.yml index 6c8b122a..9baa8a70 100644 --- a/evolinux-base/tasks/fstab.yml +++ b/evolinux-base/tasks/fstab.yml @@ -16,7 +16,7 @@ replace: '\1{{ evolinux_fstab_home_options | mandatory }}\3' notify: remount /home when: - - "' /home ' in fstab_content.stdout" + - fstab_content.stdout | regex_search('\s/home\s') - evolinux_fstab_home - name: /tmp partition is customized @@ -25,7 +25,7 @@ regexp: '([^#]\s+/tmp\s+\S+\s+)([a-z,]+)(\s+)' replace: '\1{{ evolinux_fstab_tmp_options | mandatory }}\3' when: - - "' /tmp ' in fstab_content.stdout" + - fstab_content.stdout | regex_search('\s/tmp\s') - evolinux_fstab_tmp - name: /usr partition is customized @@ -34,7 +34,7 @@ regexp: '([^#]\s+/usr\s+\S+\s+)([a-z,]+)(\s+)' replace: '\1{{ evolinux_fstab_usr_options | mandatory }}\3' when: - - "' /usr ' in fstab_content.stdout" + - fstab_content.stdout | regex_search('\s/usr\s') - evolinux_fstab_usr - name: /var partition is customized @@ -44,7 +44,7 @@ replace: '\1{{ evolinux_fstab_var_options | mandatory }}\3' notify: remount /var when: - - "' /var ' in fstab_content.stdout" + - fstab_content.stdout | regex_search('\s/var\s') - evolinux_fstab_var - name: /var/tmp is created diff --git a/evolinux-base/tasks/hardware.yml b/evolinux-base/tasks/hardware.yml index 69ab0889..8607a586 100644 --- a/evolinux-base/tasks/hardware.yml +++ b/evolinux-base/tasks/hardware.yml @@ -9,7 +9,7 @@ - name: Check if Broadcom NetXtreme II device is present shell: "lspci | grep -q 'NetXtreme II'" check_mode: no - register: broadcom + register: broadcom_netextreme_search failed_when: False changed_when: False @@ -22,7 +22,7 @@ tasks_from: basics.yml vars: apt_basics_components: "main contrib non-free" - when: broadcom|success + when: broadcom_netextreme_search.rc == 0 ## RAID @@ -53,6 +53,18 @@ when: "'Hewlett-Packard Company Smart Array' in raidmodel.stdout" - block: + - name: Add HW tool GPG key + apt_key: + # url: https://hwraid.le-vert.net/debian/hwraid.le-vert.net.gpg.key + data: "{{ lookup('file', 'hwraid.le-vert.net.gpg.key') }}" + when: ansible_distribution_release == "stretch" + + - name: Add HW tool repository + apt_repository: + repo: 'deb http://hwraid.le-vert.net/debian stretch main' + state: present + when: ansible_distribution_release == "stretch" + - name: Install packages for DELL/LSI hardware apt: name: "{{ item }}" diff --git a/evolinux-base/tasks/main.yml b/evolinux-base/tasks/main.yml index 5c1ad594..4784b084 100644 --- a/evolinux-base/tasks/main.yml +++ b/evolinux-base/tasks/main.yml @@ -5,6 +5,19 @@ when: - ansible_distribution != "Debian" or ansible_distribution_major_version | version_compare('8', '<') +- name: Apt configuration + include_role: + name: apt + vars: + apt_install_basics: "{{ evolinux_apt_replace_default_sources }}" + apt_install_evolix_public: "{{ evolinux_apt_public_sources }}" + when: evolinux_apt_include + +- name: /etc versioning with Git + include_role: + name: etc-git + when: evolinux_etcgit_include + - name: Hostname include: hostname.yml when: evolinux_hostname_include @@ -13,10 +26,6 @@ include: kernel.yml when: evolinux_kernel_include -- name: Apt configuration and packages install - include: apt.yml - when: evolinux_apt_include - - name: Fstab configuration include: fstab.yml when: evolinux_fstab_include @@ -29,14 +38,25 @@ include: system.yml when: evolinux_system_include -- name: Root user configuration - include: root.yml - when: evolinux_root_include +- name: Evomaintenance + include_role: + name: evomaintenance + when: evolinux_evomaintenance_include - name: SSH configuration include: ssh.yml when: evolinux_ssh_include +### disabled because of a memory leak +# - name: Create evolinux users +# include_role: +# name: evolinux-users +# when: evolinux_users_include + +- name: Root user configuration + include: root.yml + when: evolinux_root_include + - name: Postfix include: postfix.yml when: evolinux_postfix_include @@ -63,4 +83,34 @@ - name: Override Logmail service include: log2mail.yml - when: evolinux_packages_serveur_base + when: evolinux_log2mail_include + +- name: Minifirewall + include_role: + name: minifirewall + when: evolinux_minifirewall_include + +- name: Munin + include_role: + name: munin + when: evolinux_munin_include + +- name: Nagios/NRPE + include_role: + name: nagios-nrpe + when: evolinux_nagios_nrpe_include + +- name: fail2ban + include_role: + name: fail2ban + when: evolinux_fail2ban_include + +- name: Listupgrade + include_role: + name: listupgrade + when: evolinux_listupgrade_include + +- name: Generate ldif script + include_role: + name: generate-ldif + when: evolinux_generateldif_include diff --git a/evolinux-base/tasks/packages.yml b/evolinux-base/tasks/packages.yml index bb1f81c9..effa7c0c 100644 --- a/evolinux-base/tasks/packages.yml +++ b/evolinux-base/tasks/packages.yml @@ -13,6 +13,7 @@ - apg - conntrack - logrotate + - bash-completion - ssl-cert - ca-certificates when: evolinux_packages_system diff --git a/evolinux-base/tasks/postfix.yml b/evolinux-base/tasks/postfix.yml index 9aad67e4..84bb06a2 100644 --- a/evolinux-base/tasks/postfix.yml +++ b/evolinux-base/tasks/postfix.yml @@ -1,6 +1,6 @@ --- -- name: packages are installed +- name: Postfix packages are installed apt: name: "{{ item }}" state: present diff --git a/evolinux-base/tasks/remount_usr_rw.yml b/evolinux-base/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/evolinux-base/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/evolinux-base/tasks/root.yml b/evolinux-base/tasks/root.yml index ffe64fe1..8fb2d113 100644 --- a/evolinux-base/tasks/root.yml +++ b/evolinux-base/tasks/root.yml @@ -80,4 +80,23 @@ - "set shiftwidth=4" when: evolinux_root_vim_conf +- name: disable SSH access for root + replace: + dest: /etc/ssh/sshd_config + regexp: '^PermitRootLogin (yes|without-password|prohibit-password)' + replace: "PermitRootLogin no" + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: evolinux_root_disable_ssh + +### Disabled : it seems useless and too dangerous for now +# - name: remove root from AllowUsers directive +# replace: +# dest: /etc/ssh/sshd_config +# regexp: '^(AllowUsers ((?!root(?:@\S+)?).)*)(\sroot(?:@\S+)?|root(?:@\S+)?\s)(.*)$' +# replace: '\1\4' +# validate: '/usr/sbin/sshd -T -f %s' +# notify: reload sshd +# when: evolinux_root_disable_ssh + - meta: flush_handlers diff --git a/evolinux-base/tasks/ssh.yml b/evolinux-base/tasks/ssh.yml index 2b7273b5..e4f51a81 100644 --- a/evolinux-base/tasks/ssh.yml +++ b/evolinux-base/tasks/ssh.yml @@ -3,61 +3,45 @@ msg: "Warning: empty 'evolinux_ssh_password_auth_addresses' variable, tasks will be skipped!" when: evolinux_ssh_password_auth_addresses == [] -- name: Security directives for Evolinux +# From 'man sshd_config' : +# « If all of the criteria on the Match line are satisfied, the keywords +# on the following lines override those set in the global section of the config +# file, until either another Match line or the end of the file. +# If a keyword appears in multiple Match blocks that are satisfied, +# only the first instance of the keyword is applied. » +# +# We want to allow any user from a list of IP addresses to login with password, +# but users of the "evolix" group can't login with password from other IP addresses + +- name: Security directives for Evolinux (Debian 9 or later)" blockinfile: dest: /etc/ssh/sshd_config block: | - Match Group evolinux-sudo - PasswordAuthentication no Match Address {{ evolinux_ssh_password_auth_addresses | join(',') }} PasswordAuthentication yes + Match Group evolix + PasswordAuthentication no marker: "# {mark} EVOLINUX PASSWORD RESTRICTIONS" insertafter: EOF validate: '/usr/sbin/sshd -T -f %s' notify: reload sshd - when: not evolinux_ssh_password_auth_addresses == [] + when: + - evolinux_ssh_password_auth_addresses != [] + - ansible_distribution_major_version | version_compare('9', '>=') -# - name: verify Match Address directive -# command: "grep 'Match Address' /etc/ssh/sshd_config" -# changed_when: False -# failed_when: False -# check_mode: no -# register: grep_matchaddress_ssh -# -# - name: Add Match Address sshd directive -# lineinfile: -# dest: /etc/ssh/sshd_config -# line: "\nMatch Address {{ evolinux_ssh_password_auth_addresses | join(',') }}\n PasswordAuthentication yes" -# insertafter: '# +ForceCommand cvs server' -# validate: '/usr/sbin/sshd -T -f %s' -# notify: reload sshd -# when: evolinux_ssh_match_address and grep_matchaddress_ssh.rc != 0 and evolinux_ssh_password_auth_addresses != [] -# -# - name: Modify Match Address sshd directive -# replace: -# dest: /etc/ssh/sshd_config -# regexp: '^(Match Address ((?!{{ item }}).)*)$' -# replace: '\1,{{ item }}' -# validate: '/usr/sbin/sshd -T -f %s' -# with_items: "{{ evolinux_ssh_password_auth_addresses }}" -# notify: reload sshd -# when: evolinux_ssh_match_address and grep_matchaddress_ssh.rc == 0 -# -# - name: Add Match Group sudo without password -# lineinfile: -# dest: /etc/ssh/sshd_config -# line: "\nMatch Group sudo\n PasswordAuthentication no" -# insertbefore: '^Match Address' -# validate: '/usr/sbin/sshd -T -f %s' -# notify: reload sshd - -- name: disable SSH access for root - replace: +- name: Security directives for Evolinux (Jessie) + blockinfile: dest: /etc/ssh/sshd_config - regexp: '^PermitRootLogin (yes|without-password)' - replace: "PermitRootLogin no" + block: | + Match Address {{ evolinux_ssh_password_auth_addresses | join(',') }} + PasswordAuthentication yes + marker: "# {mark} EVOLINUX PASSWORD RESTRICTIONS BY ADDRESS" + insertafter: EOF + validate: '/usr/sbin/sshd -T -f %s' notify: reload sshd - when: evolinux_ssh_disable_root + when: + - evolinux_ssh_password_auth_addresses != [] + - ansible_distribution_release == "jessie" # We disable AcceptEnv because it can be a security issue, but also because we # do not want clients to push their environment variables like LANG. @@ -77,4 +61,38 @@ notify: reload sshd when: ansible_distribution_major_version | version_compare('9', '>=') +- name: "Get current user" + command: logname + register: logname + check_mode: no + changed_when: False + when: evolinux_ssh_allow_current_user + +# we must double-escape caracters, because python +- name: verify AllowUsers directive + shell: "grep -E '^AllowUsers' /etc/ssh/sshd_config" + changed_when: False + failed_when: False + register: grep_allowusers_ssh + check_mode: no + when: evolinux_ssh_allow_current_user + +- name: "Add AllowUsers sshd directive for current user" + lineinfile: + dest: /etc/ssh/sshd_config + line: "\nAllowUsers {{ logname.stdout }}" + insertafter: 'Subsystem' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: evolinux_ssh_allow_current_user and grep_allowusers_ssh.rc != 0 + +- name: "Modify AllowUsers sshd directive for current user" + replace: + dest: /etc/ssh/sshd_config + regexp: '^(AllowUsers ((?!{{ logname.stdout }}).)*)$' + replace: '\1 {{ logname.stdout }}' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: evolinux_ssh_allow_current_user and grep_allowusers_ssh.rc == 0 + - meta: flush_handlers diff --git a/evolinux-base/tasks/system.yml b/evolinux-base/tasks/system.yml index 261ef1a9..4ef08fa3 100644 --- a/evolinux-base/tasks/system.yml +++ b/evolinux-base/tasks/system.yml @@ -33,7 +33,8 @@ # TODO : find a way to force the console-data configuration # non-interactively (like tzdata ↑) -- include: remount_usr_rw.yml +- include_role: + name: remount-usr - name: Ensure automagic vim conf is disabled lineinfile: @@ -59,7 +60,7 @@ - name: Set /etc/adduser.conf DIR_MODE to 0700 replace: dest: /etc/adduser.conf - regexp: "^DIR_MODE=.*$" + regexp: "^DIR_MODE=0755$" replace: "DIR_MODE=0700" when: evolinux_system_dirmode_adduser @@ -116,29 +117,56 @@ ## alert5 -- name: Install alert5 init script +- name: Install alert5 init script (jessie/stretch) template: - src: system/init_alert5.j2 + src: system/alert5.sysvinit.j2 dest: /etc/init.d/alert5 force: no mode: "0755" - when: evolinux_system_alert5_init + when: + - evolinux_system_alert5_init + - ansible_distribution_release == "jessie" or ansible_distribution_release == "stretch" - -#TODO: switch service/systemd modules with Ansible 2.2+ - -- name: Enable alert5 init script +- name: Enable alert5 init script (jessie/stretch) service: name: alert5 enabled: yes - when: evolinux_system_alert5_init and evolinux_system_alert5_enable + when: + - evolinux_system_alert5_init + - evolinux_system_alert5_enable + - ansible_distribution_release == "jessie" or ansible_distribution_release == "stretch" -# - name: Enable alert5 init script -# systemd: -# name: alert5 -# daemon_reload: yes -# enabled: yes -# when: evolinux_system_alert5_init and evolinux_system_alert5_enable + + +- name: Install alert5 init script (buster) + template: + src: system/alert5.sh.j2 + dest: /usr/share/scripts/alert5.sh + force: no + mode: "0755" + when: + - evolinux_system_alert5_init + - ansible_distribution_major_version | version_compare('10', '>=') + +- name: Install alert5 service (buster) + copy: + src: alert5.service + dest: /etc/systemd/system/alert5.service + force: yes + mode: "0755" + when: + - evolinux_system_alert5_init + - ansible_distribution_major_version | version_compare('10', '>=') + +- name: Enable alert5 init script (buster) + systemd: + name: alert5 + daemon_reload: yes + enabled: yes + when: + - evolinux_system_alert5_init + - evolinux_system_alert5_enable + - ansible_distribution_major_version | version_compare('10', '>=') ## network interfaces diff --git a/evolinux-base/templates/system/alert5.sh.j2 b/evolinux-base/templates/system/alert5.sh.j2 new file mode 100644 index 00000000..7949af28 --- /dev/null +++ b/evolinux-base/templates/system/alert5.sh.j2 @@ -0,0 +1,7 @@ +#!/bin/sh + +## sends a mail when booting +date | mail -s'boot/reboot' {{ reboot_alert_email or general_alert_email | mandatory }} + +## starts the firewall +#/etc/init.d/minifirewall start diff --git a/evolinux-base/templates/system/init_alert5.j2 b/evolinux-base/templates/system/alert5.sysvinit.j2 similarity index 100% rename from evolinux-base/templates/system/init_alert5.j2 rename to evolinux-base/templates/system/alert5.sysvinit.j2 diff --git a/admin-users/.kitchen.yml b/evolinux-users/.kitchen.yml similarity index 92% rename from admin-users/.kitchen.yml rename to evolinux-users/.kitchen.yml index f9ea107a..0c97cc85 100644 --- a/admin-users/.kitchen.yml +++ b/evolinux-users/.kitchen.yml @@ -31,7 +31,7 @@ suites: playbook: ./tests/test.yml verifier: patterns: - - admin-users/tests/spec/admin-users_spec.rb + - evolinux-users/tests/spec/evolinux-users_spec.rb bundler_path: '/usr/local/bin' rspec_path: '/usr/local/bin' diff --git a/admin-users/README.md b/evolinux-users/README.md similarity index 50% rename from admin-users/README.md rename to evolinux-users/README.md index 68b0044d..439bd898 100644 --- a/admin-users/README.md +++ b/evolinux-users/README.md @@ -1,6 +1,6 @@ -# admin-users +# evolinux-users -Creates admin users accounts, based on a configuration data structure. +Creates evolinux users accounts, based on a configuration data structure. ## Tasks @@ -8,20 +8,26 @@ Everything is in the `tasks/main.yml` file. ## Available variables -The variable `admin_users` must be a "dict" of one or more users : +The variable `evolinux_users` must be a "dict" of one or more users : ``` -admin_users: +evolinux_users: foo: name: foo uid: 1001 fullname: 'Mr Foo' + groups: "baz" password_hash: 'sdfgsdfgsdfgsdfg' ssh_key: 'ssh-rsa AZERTYXYZ' bar: name: bar uid: 1002 fullname: 'Mr Bar' + groups: + - "baz" + - "qux" password_hash: 'gsdfgsdfgsdfgsdf' - ssh_key: 'ssh-rsa QWERTYUIOP' + ssh_keys: + - 'ssh-rsa QWERTYUIOP' + - 'ssh-ed25519 QWERTYUIOP' ``` diff --git a/evolinux-users/defaults/main.yml b/evolinux-users/defaults/main.yml new file mode 100644 index 00000000..d7d6f958 --- /dev/null +++ b/evolinux-users/defaults/main.yml @@ -0,0 +1,4 @@ +--- +evolinux_users: {} +evolinux_sudo_group: "evolinux-sudo" +evolinux_root_disable_ssh: True diff --git a/admin-users/handlers/main.yml b/evolinux-users/handlers/main.yml similarity index 100% rename from admin-users/handlers/main.yml rename to evolinux-users/handlers/main.yml diff --git a/admin-users/meta/main.yml b/evolinux-users/meta/main.yml similarity index 88% rename from admin-users/meta/main.yml rename to evolinux-users/meta/main.yml index 006768d3..9bae9e73 100644 --- a/admin-users/meta/main.yml +++ b/evolinux-users/meta/main.yml @@ -1,6 +1,6 @@ galaxy_info: author: Evolix - description: Creates admin users accounts. + description: Creates evolinux users accounts. issue_tracker_url: https://forge.evolix.org/projects/ansible-roles/issues diff --git a/admin-users/tasks/user.yml b/evolinux-users/tasks/account.yml similarity index 72% rename from admin-users/tasks/user.yml rename to evolinux-users/tasks/account.yml index 94f1a0c3..1ed142f9 100644 --- a/admin-users/tasks/user.yml +++ b/evolinux-users/tasks/account.yml @@ -35,19 +35,22 @@ update_password: on_create when: loginisbusy.rc != 0 and uidisbusy.rc == 0 -- name: "Create {{ admin_users_group }} group (Debian 9 or later)" +- name: "Create secondary groups" group: - name: "{{ admin_users_group }}" - when: ansible_distribution_major_version | version_compare('9', '>=') + name: "{{ group }}" + with_items: "{{ user.groups }}" + loop_control: + loop_var: group + when: user.groups is defined -- name: "Add user to {{ admin_users_group }} group (Debian 9 or later)" +- name: "Add user '{{ user.name }}' to secondary groups" user: name: '{{ user.name }}' - groups: '{{ admin_users_group }}' + groups: "{{ user.groups }}" append: yes - when: ansible_distribution_major_version | version_compare('9', '>=') + when: user.groups is defined -- name: "Fix perms on homedirectory for '{{ user.name }}'" +- name: "Fix perms on home directory for '{{ user.name }}'" file: name: '/home/{{ user.name }}' mode: "0700" diff --git a/evolinux-users/tasks/main.yml b/evolinux-users/tasks/main.yml new file mode 100644 index 00000000..ec1400bd --- /dev/null +++ b/evolinux-users/tasks/main.yml @@ -0,0 +1,20 @@ +--- + +- fail: + msg: only compatible with Debian >= 8 + when: + - ansible_distribution != "Debian" or ansible_distribution_major_version | version_compare('8', '<') + +- debug: + msg: "Warning: empty 'evolinux_users' variable, tasks will be skipped!" + when: evolinux_users == {} + +- name: Create user accounts + include: user.yml + vars: + user: "{{ item.value }}" + with_dict: "{{ evolinux_users }}" + when: evolinux_users != {} + +- include: root_disable_ssh.yml + when: evolinux_root_disable_ssh diff --git a/evolinux-users/tasks/profile.yml b/evolinux-users/tasks/profile.yml new file mode 100644 index 00000000..99af2512 --- /dev/null +++ b/evolinux-users/tasks/profile.yml @@ -0,0 +1,16 @@ +--- + +- name: search profile for presence of evomaintenance + command: 'grep -q "trap.*sudo.*evomaintenance.sh"' + changed_when: False + failed_when: False + register: grep_profile_evomaintenance + +# Don't add the trap if it is present or commented +- name: "Add evomaintenance trap for '{{ user.name }}'" + lineinfile: + state: present + dest: '/home/{{ user.name }}/.profile' + insertafter: EOF + line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0' + when: grep_profile_evomaintenance.rc != 0 diff --git a/evolinux-users/tasks/root_disable_ssh.yml b/evolinux-users/tasks/root_disable_ssh.yml new file mode 100644 index 00000000..7906307f --- /dev/null +++ b/evolinux-users/tasks/root_disable_ssh.yml @@ -0,0 +1,17 @@ +--- + +- name: disable root login + replace: + dest: /etc/ssh/sshd_config + regexp: '^PermitRootLogin (yes|without-password|prohibit-password)' + replace: "PermitRootLogin no" + notify: reload sshd + +### Disabled : it seems useless and too dangerous for now +# - name: remove root from AllowUsers directive +# replace: +# dest: /etc/ssh/sshd_config +# regexp: '^(AllowUsers ((?!root(?:@\S+)?).)*)(\sroot(?:@\S+)?|root(?:@\S+)?\s)(.*)$' +# replace: '\1\4' +# validate: '/usr/sbin/sshd -T -f %s' +# notify: reload sshd diff --git a/admin-users/tasks/ssh.yml b/evolinux-users/tasks/ssh.yml similarity index 68% rename from admin-users/tasks/ssh.yml rename to evolinux-users/tasks/ssh.yml index d74a51f2..8982dd6c 100644 --- a/admin-users/tasks/ssh.yml +++ b/evolinux-users/tasks/ssh.yml @@ -14,10 +14,21 @@ user: "{{ user.name }}" key: "{{ user.ssh_key }}" state: present + when: user.ssh_key is defined + +- name: "Add user's SSH public keys for '{{ user.name }}'" + authorized_key: + user: "{{ user.name }}" + key: "{{ ssk_key }}" + state: present + with_items: "{{ user.ssh_keys }}" + loop_control: + loop_var: ssk_key + when: user.ssh_keys is defined # we must double-escape caracters, because python - name: verify AllowUsers directive - shell: "egrep '^AllowUsers' /etc/ssh/sshd_config" + shell: "grep -E '^AllowUsers' /etc/ssh/sshd_config" changed_when: False failed_when: False register: grep_allowusers_ssh @@ -35,32 +46,37 @@ - name: "Modify AllowUsers sshd directive for '{{ user.name }}'" replace: dest: /etc/ssh/sshd_config - regexp: '^(AllowUsers ((?!{{ user.name }}).)*)$' + regexp: '^(AllowUsers ((?!\b{{ user.name }}\b).)*)$' replace: '\1 {{ user.name }}' validate: '/usr/sbin/sshd -T -f %s' notify: reload sshd when: grep_allowusers_ssh.rc == 0 -- name: verify Match User directive +- name: "verify Match User directive" command: "grep 'Match User' /etc/ssh/sshd_config" changed_when: False failed_when: False register: grep_matchuser_ssh check_mode: no -- name: "Add Match User sshd directive for '{{ user.name }}'" +- name: "Add Match User sshd directive for '{{ user.name }}' (Jessie)" lineinfile: dest: /etc/ssh/sshd_config line: "\nMatch User {{ user.name }}\n PasswordAuthentication no" + insertafter: "# END EVOLINUX PASSWORD RESTRICTIONS BY ADDRESS" validate: '/usr/sbin/sshd -T -f %s' notify: reload sshd - when: grep_matchuser_ssh.rc != 0 + when: + - ansible_distribution_release == "jessie" + - grep_matchuser_ssh.rc != 0 -- name: "Modify Match User's sshd directive for '{{ user.name }}'" +- name: "Modify Match User's sshd directive for '{{ user.name }}' (Jessie)" replace: dest: /etc/ssh/sshd_config regexp: '^(Match User ((?!{{ user.name }}).)*)$' replace: '\1,{{ user.name }}' validate: '/usr/sbin/sshd -T -f %s' notify: reload sshd - when: grep_matchuser_ssh.rc == 0 + when: + - ansible_distribution_release == "jessie" + - grep_matchuser_ssh.rc == 0 diff --git a/evolinux-users/tasks/sudo_jessie.yml b/evolinux-users/tasks/sudo_jessie.yml new file mode 100644 index 00000000..f675954e --- /dev/null +++ b/evolinux-users/tasks/sudo_jessie.yml @@ -0,0 +1,18 @@ +--- + +- name: "Verify Evolinux sudoers file presence (jessie)" + template: + src: sudoers_jessie.j2 + dest: /etc/sudoers.d/evolinux + force: no + mode: "0440" + validate: '/usr/sbin/visudo -cf %s' + register: copy_sudoers_evolinux + +- name: "Add user in sudoers file for '{{ user.name }}' (jessie)" + replace: + dest: /etc/sudoers.d/evolinux + regexp: '^(User_Alias\s+ADMINS\s+=((?!{{ user.name }}).)*)$' + replace: '\1,{{ user.name }}' + validate: '/usr/sbin/visudo -cf %s' + when: not copy_sudoers_evolinux.changed diff --git a/evolinux-users/tasks/sudo_stretch.yml b/evolinux-users/tasks/sudo_stretch.yml new file mode 100644 index 00000000..f77ae484 --- /dev/null +++ b/evolinux-users/tasks/sudo_stretch.yml @@ -0,0 +1,20 @@ +--- + +- name: "Verify Evolinux sudoers file presence (Debian 9 or later)" + template: + src: sudoers_stretch.j2 + dest: /etc/sudoers.d/evolinux + force: no + validate: '/usr/sbin/visudo -cf %s' + register: copy_sudoers_evolinux + +- name: "Create evolinux-sudo group (Debian 9 or later)" + group: + name: "{{ evolinux_sudo_group }}" + system: yes + +- name: "Add user to evolinux-sudo group (Debian 9 or later)" + user: + name: '{{ user.name }}' + groups: "{{ evolinux_sudo_group }}" + append: yes diff --git a/evolinux-users/tasks/user.yml b/evolinux-users/tasks/user.yml new file mode 100644 index 00000000..73fea728 --- /dev/null +++ b/evolinux-users/tasks/user.yml @@ -0,0 +1,15 @@ +--- + +- include: account.yml + +- include: profile.yml + +- include: ssh.yml + +- include: sudo_jessie.yml + when: ansible_distribution_release == "jessie" + +- include: sudo_stretch.yml + when: ansible_distribution_major_version | version_compare('9', '>=') + +- meta: flush_handlers diff --git a/admin-users/templates/sudoers_jessie.j2 b/evolinux-users/templates/sudoers_jessie.j2 similarity index 100% rename from admin-users/templates/sudoers_jessie.j2 rename to evolinux-users/templates/sudoers_jessie.j2 diff --git a/admin-users/templates/sudoers_stretch.j2 b/evolinux-users/templates/sudoers_stretch.j2 similarity index 75% rename from admin-users/templates/sudoers_stretch.j2 rename to evolinux-users/templates/sudoers_stretch.j2 index 8de1bbc6..289a65ee 100644 --- a/admin-users/templates/sudoers_stretch.j2 +++ b/evolinux-users/templates/sudoers_stretch.j2 @@ -5,5 +5,5 @@ Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh, /usr/share/scripts nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_procs nagios ALL = (clamav) NOPASSWD: /usr/bin/clamscan /tmp/safe.txt -%evolinux-sudo ALL=(ALL:ALL) ALL -%evolinux-sudo ALL = NOPASSWD: MAINT +%{{ evolinux_sudo_group }} ALL=(ALL:ALL) ALL +%{{ evolinux_sudo_group }} ALL = NOPASSWD: MAINT diff --git a/admin-users/tests/spec/admin-users_spec.rb b/evolinux-users/tests/spec/evolinux-users_spec.rb similarity index 100% rename from admin-users/tests/spec/admin-users_spec.rb rename to evolinux-users/tests/spec/evolinux-users_spec.rb diff --git a/admin-users/tests/test.yml b/evolinux-users/tests/test.yml similarity index 94% rename from admin-users/tests/test.yml rename to evolinux-users/tests/test.yml index 06c29643..f622eebf 100644 --- a/admin-users/tests/test.yml +++ b/evolinux-users/tests/test.yml @@ -2,7 +2,7 @@ - hosts: test-kitchen vars: - admin_users: + evolinux_users: foo: name: foo uid: 1001 @@ -20,4 +20,4 @@ # state: directory roles: - - role: admin-users + - role: evolinux-users diff --git a/evomaintenance/defaults/main.yml b/evomaintenance/defaults/main.yml index fc584481..2d0bf1b6 100644 --- a/evomaintenance/defaults/main.yml +++ b/evomaintenance/defaults/main.yml @@ -17,4 +17,7 @@ evomaintenance_urgency_tel: "06.00.00.00.00" evomaintenance_realm: "{{ ansible_domain }}" -evomaintenance_hosts: [] +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +evomaintenance_hosts: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" diff --git a/fail2ban/defaults/main.yml b/fail2ban/defaults/main.yml index 2fe40951..73cd46cb 100644 --- a/fail2ban/defaults/main.yml +++ b/fail2ban/defaults/main.yml @@ -1,4 +1,11 @@ --- general_alert_email: "root@localhost" fail2ban_alert_email: Null -fail2ban_ignore_ips: [] + +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +fail2ban_ignore_ips: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" + +fail2ban_wordpress: False +fail2ban_roundcube: False diff --git a/fail2ban/files/roundcube.conf b/fail2ban/files/roundcube.conf new file mode 100644 index 00000000..d4ad016a --- /dev/null +++ b/fail2ban/files/roundcube.conf @@ -0,0 +1,2 @@ +[Definition] +failregex = Login failed for .*. from diff --git a/fail2ban/files/wordpress-hard.conf b/fail2ban/files/wordpress-hard.conf new file mode 100644 index 00000000..0eba3cf0 --- /dev/null +++ b/fail2ban/files/wordpress-hard.conf @@ -0,0 +1,31 @@ +# Fail2Ban configuration file soft +# +# Author: Charles Lecklider +# + +[INCLUDES] + +# Read common prefixes. If any customizations available -- read them from +# common.local +before = common.conf + + +[Definition] + +_daemon = (?:wordpress|wp) + +# Option: failregex +# Notes.: regex to match the password failures messages in the logfile. The +# host must be matched by a group named "host". The tag "" can +# be used for standard IP/hostname matching and is only an alias for +# (?:::f{4,6}:)?(?P[\w\-.^_]+) +# Values: TEXT +# +failregex = ^%(__prefix_line)sAuthentication failure for .* from $ + ^%(__prefix_line)sXML-RPC authentication failure from $ + +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# +ignoreregex = diff --git a/fail2ban/files/wordpress-soft.conf b/fail2ban/files/wordpress-soft.conf new file mode 100644 index 00000000..345aab68 --- /dev/null +++ b/fail2ban/files/wordpress-soft.conf @@ -0,0 +1,33 @@ +# Fail2Ban configuration file hard +# +# Author: Charles Lecklider +# + +[INCLUDES] + +# Read common prefixes. If any customizations available -- read them from +# common.local +before = common.conf + + +[Definition] + +_daemon = (?:wordpress|wp) + +# Option: failregex +# Notes.: regex to match the password failures messages in the logfile. The +# host must be matched by a group named "host". The tag "" can +# be used for standard IP/hostname matching and is only an alias for +# (?:::f{4,6}:)?(?P[\w\-.^_]+) +# Values: TEXT +# +failregex = ^%(__prefix_line)sAuthentication attempt for unknown user .* from ( via XML-RPC)?$ + ^%(__prefix_line)sBlocked authentication attempt for .* from ( via XML-RPC)?$ + ^%(__prefix_line)sBlocked user enumeration attempt from $ + ^%(__prefix_line)sPingback error .* generated from $ + +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# +ignoreregex = diff --git a/fail2ban/tasks/main.yml b/fail2ban/tasks/main.yml index 7a47a0ce..579e143d 100644 --- a/fail2ban/tasks/main.yml +++ b/fail2ban/tasks/main.yml @@ -2,13 +2,16 @@ # We have to copy the local jail before installing the package # or we risk being jailed by fail2ban -- name: Prepare /etc/fail2ban +- name: Prepare fail2ban hierarchy file: - path: /etc/fail2ban + path: "{{ item }}" state: directory owner: root group: root mode: "0755" + with_items: + - "/etc/fail2ban" + - "/etc/fail2ban/filter.d" tags: - fail2ban @@ -22,14 +25,6 @@ tags: - fail2ban -- name: package is installed - apt: - name: fail2ban - state: present - tags: - - fail2ban - - packages - - name: custom filters are installed copy: src: "{{ item }}" @@ -38,6 +33,17 @@ with_items: - dovecot-evolix.conf - sasl-evolix.conf + - wordpress-soft.conf + - wordpress-hard.conf + - roundcube.conf notify: restart fail2ban tags: - fail2ban + +- name: package is installed + apt: + name: fail2ban + state: present + tags: + - fail2ban + - packages diff --git a/fail2ban/templates/jail.local.j2 b/fail2ban/templates/jail.local.j2 index 2f4d6bc3..73b5f21f 100644 --- a/fail2ban/templates/jail.local.j2 +++ b/fail2ban/templates/jail.local.j2 @@ -26,3 +26,30 @@ action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(proto %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] action = %(action_mwl)s + +{% if fail2ban_wordpress %} +[wordpress-hard] +enabled = true +port = http,https +filter = wordpress-hard +logpath = /var/log/auth.log +maxretry = 1 +findtime = 300 + +[wordpress-soft] +enabled = true +port = http,https +filter = wordpress-soft +logpath = /var/log/auth.log +maxretry = 5 +findtime = 300 +{% endif %} + +{% if fail2ban_roundcube %} +[roundcube] +enabled = true +port = http,https +filter = roundcube +logpath = /var/lib/roundcube/logs/errors +maxretry = 5 +{% endif %} diff --git a/filebeat/meta/main.yml b/filebeat/meta/main.yml index 4e6139af..37aa6319 100644 --- a/filebeat/meta/main.yml +++ b/filebeat/meta/main.yml @@ -12,6 +12,7 @@ galaxy_info: - name: Debian versions: - jessie + - stretch dependencies: [] # List your role dependencies here, one per line. diff --git a/filebeat/tasks/main.yml b/filebeat/tasks/main.yml index bc038b93..75f4bc2b 100644 --- a/filebeat/tasks/main.yml +++ b/filebeat/tasks/main.yml @@ -20,7 +20,7 @@ - name: Elastic sources list is available apt_repository: repo: "deb https://artifacts.elastic.co/packages/5.x/apt stable main" - filename: elastic.list + filename: elastic state: present update_cache: yes tags: @@ -36,7 +36,7 @@ - packages - name: Filebeat service is enabled - service: + systemd: name: filebeat enabled: yes @@ -59,31 +59,11 @@ when: filebeat_logstash_plugin and logstash_plugin.stat.exists - block: - - name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - check_mode: no - register: usr_partition - - - name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 + - include_role: + name: remount-usr - name: Logstash plugin is installed command: /usr/share/logstash/bin/logstash-plugin install logstash-input-beats - - - name: /usr is remounted - command: mount -oremount /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 when: - filebeat_logstash_plugin - logstash_plugin.stat.exists diff --git a/generate-ldif/README.md b/generate-ldif/README.md new file mode 100644 index 00000000..a71be619 --- /dev/null +++ b/generate-ldif/README.md @@ -0,0 +1,22 @@ +# generate-ldif + +Install generateldif ; a script for building an ldif file, ready to import into LDAP. + +## Tasks + +The roles install the script, but doesn't run it. + +A separate `exec.yml` task file can be played manually in playbooks or roles to execute the script. Example : + +``` +- include_role: + name: generate-ldif + tasks_from: exec.yml +``` +## Variables + +* `general_scripts_dir` : parent directory for the script +* `client_number` : client number (default: `XXX`) +* `monitoring_mode` : `everytime` or `worktime` (default: `everytime`) +* `monitoring_type` : `icmp` or `nrpe` (default: `icmp`) +* `monitoring_timeout` : timeout for nrpe checks, in seconds (default: `10`) diff --git a/generate-ldif/defaults/main.yml b/generate-ldif/defaults/main.yml new file mode 100644 index 00000000..48bd19fc --- /dev/null +++ b/generate-ldif/defaults/main.yml @@ -0,0 +1,7 @@ +--- +general_scripts_dir: "/usr/share/scripts" + +client_number: XXX +monitoring_mode: "everytime" +monitoring_type: "icmp" +monitoring_timeout: "10" diff --git a/generate-ldif/tasks/exec.yml b/generate-ldif/tasks/exec.yml new file mode 100644 index 00000000..6450c6bc --- /dev/null +++ b/generate-ldif/tasks/exec.yml @@ -0,0 +1,15 @@ +--- +- name: run generateldif + command: '{{ general_scripts_dir }}/generateldif.sh' + register: generateldif_run + changed_when: False + failed_when: False + check_mode: no + tags: + - generateldif-exec + +- debug: + var: generateldif_run.stdout_lines + verbosity: 1 + tags: + - generateldif-exec diff --git a/generate-ldif/tasks/main.yml b/generate-ldif/tasks/main.yml new file mode 100644 index 00000000..35da06be --- /dev/null +++ b/generate-ldif/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- include_role: + name: remount-usr + when: general_scripts_dir | search("/usr") + +- name: "copy generateldif.sh" + template: + src: templates/generateldif.sh.j2 + dest: '{{ general_scripts_dir }}/generateldif.sh' + owner: root + group: root + mode: "0750" diff --git a/generate-ldif/templates/generateldif.sh.j2 b/generate-ldif/templates/generateldif.sh.j2 new file mode 100755 index 00000000..0f3abcf2 --- /dev/null +++ b/generate-ldif/templates/generateldif.sh.j2 @@ -0,0 +1,542 @@ +#!/bin/sh + +if [ $(id -u) != 0 ]; then + echo "You must be root" 2>&1 + exit 1 +fi + +is_pkg_installed() { + dpkg -l "$1" 2>/dev/null | grep -q '^ii' +} + +get_pkg_version() { + dpkg-query -W -f='${Version}\n' "$1" | \ + sed 's/[~+-].\+//' | sed 's/.\+://' | sed 's/p.*//' | cut -d'.' -f1,2 +} + +clientNumber="{{ client_number | mandatory }}" +monitoringMode="{{ monitoring_mode | mandatory }}" +monitoringType="{{ monitoring_type | mandatory }}" +monitoringTimeout="{{ monitoring_timeout | mandatory }}" +isActive="TRUE" +NagiosEnabled="TRUE" + +EvoComputerName=$(hostname -s) +dnsPTRrecord=$(hostname -f) +HardwareMark=$(dmidecode -s system-manufacturer | grep -v '^#') +computerIP=$(hostname -i | cut -d' ' -f1) +computerOS=$(lsb_release -s -d | sed 's#\..##') +computerKernel=$(uname -r) +HardwareSerial=$(dmidecode -s system-serial-number | grep -v '^#') + +type="baremetal" +lscpu | grep -q KVM && type="kvm" +lscpu | grep -q Oracle && type="virtualbox" + +if [ "$type" = "kvm" ]; then + HardwareMark="KVM" + HardwareModel="Virtual Machine" + + cpuMark=$(lscpu | grep Vendor | tr -s '\t' ' ' | cut -d' ' -f3) + cpuModel="Virtual $(lscpu | grep "Model name" | tr -s '\t' ' ' | cut -d' ' -f3-), $(nproc) vCPU" + cpuFreq="$(lscpu | grep "CPU MHz" | tr -s '\t' ' ' | cut -d' ' -f3-)MHz" +elif [ "$type" = "virtualbox" ]; then + HardwareMark="VirtualBox" + HardwareModel="Virtual Machine" + + cpuMark=$(lscpu | grep Vendor | tr -s '\t' ' ' | cut -d' ' -f3) + cpuModel="Virtual $(lscpu | grep "Model name" | tr -s '\t' ' ' | cut -d' ' -f3-), $(nproc) vCPU" + cpuFreq="$(lscpu | grep "CPU MHz" | tr -s '\t' ' ' | cut -d' ' -f3-)MHz" +else + HardwareModel=$(dmidecode -s system-product-name | grep -v '^#') + + cpuMark=$(dmidecode -s processor-manufacturer | grep -v '^#' | head -1) + cpuModel=$(dmidecode -s processor-version | grep -v '^#' | head -1) + cpuFreq=$(dmidecode -s processor-frequency | grep -v '^#' | head -1) +fi + +# lspci is not available on OpenVZ container. +if ( test -d /proc/vz && ! test -d /proc/bc ); then + screen0Mark="No screen on OpenVZ container" + screen0Model="No screen on OpenVZ container" + sdaSize="Total SIMFS $(df -h -t simfs --total | tail -1 | tr -s '\t' ' ' | cut -d' ' -f2)" +else + screen0Mark=$(lspci -q -vm | grep VGA -A3 | grep Vendor | tr -d '\t' | cut -d':' -f2 | head -1) + screen0Model=$(lspci -q -vm | grep VGA -A3 | grep Device | tr -d '\t' | cut -d':' -f2 | head -1) + sdaSize=$(lsblk -d -r -n -o TYPE,SIZE | grep disk | sed 's/^disk //'| xargs | sed 's/ / + /g') + raidModel=$(lspci -q -vm | grep RAID -A3 | grep Device | tr -d '\t' | cut -d':' -f2 | head -1) +fi + +if (test -b /dev/vda); then + sdaModel="Virtual VirtIO Disk" +elif [ -d /proc/vz ] && [ ! -d /proc/bc ]; then + sdaModel="OpenVZ SIMFS disk" +else + hdparm -I /dev/sda 2>&1 | grep -q bad + if [ $? -eq 0 ]; then + if (test -n "${raidModel}"); then + sdaModel=${raidModel} + else + sdaModel="Model unknown, RAID HW?" + fi + else + sdaModel=$(hdparm -I /dev/sda | grep Model | tr -s '\t' ' ' | cut -d' ' -f4-) + fi +fi + +ldif_file="/root/${EvoComputerName}.$(date +"%Y%m%d%H%M%S").ldif" + +computer_dn="EvoComputerName=${EvoComputerName},ou=computer,dc=evolix,dc=net" + +# Generic services. +cat < "${ldif_file}" +## Generated on $(date --iso-8601=seconds) +## Can be injected in LDAP with this command: +# ldapvi --profile evolix --add --in ${EvoComputerName}.ldif + +dn: ${computer_dn} +dnsArecord: ${EvoComputerName} +EvoComputerName: ${EvoComputerName} +HardwareMark: ${HardwareMark} +HardwareModel: ${HardwareModel} +dnsZone: evolix.net +objectClass: EvoComputer +objectClass: top +computerIP: ${computerIP} +dnsPTRrecord: ${dnsPTRrecord} +computerOS: ${computerOS} +computerKernel: Linux ${computerKernel} +isActive: ${isActive} +NagiosEnabled: ${NagiosEnabled} +NagiosComments: ${monitoringType},${monitoringMode},${monitoringTimeout} +HardwareSerial: ${HardwareSerial} +clientNumber: ${clientNumber} +EOT + +# CPU +if [ -n "${cpuMark}" ]; then + cat <> "${ldif_file}" + +dn: HardwareName=cpu0,${computer_dn} +HardwareMark: ${cpuMark} +objectClass: EvoHardware +HardwareName: cpu0 +HardwareSize: ${cpuFreq} +HardwareType: CPU +HardwareModel: ${cpuModel} +EOT +fi + +# Memory +mem=$(free -h | grep Mem: | tr -s ' ' | cut -d ' ' -f2) +if [ -n "${mem}" ]; then + cat <> "${ldif_file}" + +dn: HardwareName=ram0,${computer_dn} +HardwareName: ram0 +objectClass: EvoHardware +HardwareSize: ${mem} +HardwareType: mem +NagiosEnabled: TRUE +EOT +fi + +# Screen +swap=$(free -h | grep Swap: | tr -s ' ' | cut -d ' ' -f2) +if [ -n "${screen0Mark}" ]; then + cat <> "${ldif_file}" + +dn: HardwareName=screen0,${computer_dn} +HardwareMark: ${screen0Mark} +HardwareName: screen0 +objectClass: EvoHardware +HardwareModel: ${screen0Model} +HardwareType: video +EOT +fi + +# /dev/sda +if [ -n "${sdaModel}" ]; then + cat <> "${ldif_file}" + +dn: HardwareName=sda,${computer_dn} +objectClass: EvoHardware +HardwareName: sda +HardwareSize: ${sdaSize} +HardwareType: disk +HardwareModel: ${sdaModel} +HardwarePartitioncount: 1 +NagiosEnabled: TRUE +EOT +fi + +# Swap +swap=$(free -h | grep Swap: | tr -s ' ' | cut -d ' ' -f2) +if [ -n "${swap}" ]; then + cat <> "${ldif_file}" + +dn: HardwareName=swap,${computer_dn} +objectClass: EvoHardware +HardwareName: swap +HardwareSize: ${swap} +HardwareType: mem +NagiosEnabled: TRUE +EOT +fi + +# NRPE +nrpe_version=$(get_pkg_version nagios-nrpe-server) +if [ -n "${nrpe_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=nrpe,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: TCP +ServiceVersion: NRPE ${nrpe_version} +objectClass: EvoService +ServiceName: nrpe +ipServicePort: 5666 +ServiceType: monitoring +EOT +fi + +# Postfix +postfix_version=$(get_pkg_version postfix) +if [ -n "${postfix_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=postfix,${computer_dn} +ipServiceProtocol: tcp +NagiosEnabled: TRUE +objectClass: EvoService +ServiceName: postfix +ipServicePort: 25 +ServiceType: smtp +ServiceVersion: Postfix ${postfix_version} +EOT +fi + +# OpenSSH +openssh_version=$(get_pkg_version openssh-server) +if [ -n "${openssh_version}" ]; then + opensshFingerprintRSA=$(ssh-keyscan -t rsa localhost 2>/dev/null\ + | sed -e 's/localhost //' -e 's/ssh-rsa /ssh-rsa,/') + opensshFingerprintED25519=$(ssh-keyscan -t ed25519 localhost 2>/dev/null\ + | sed -e 's/localhost //' -e 's/ssh-ed25519 /ssh-ed25519,/') + opensshFingerprintECDSA=$(ssh-keyscan -t ecdsa-sha2-nistp256 localhost 2>/dev/null\ + | sed -e 's/localhost //' -e 's/ecdsa-sha2-nistp256 /ecdsa-sha2-nistp256,/') + opensshFingerprint="${opensshFingerprintRSA}${opensshFingerprintRSA:+;}${opensshFingerprintED25519}${opensshFingerprintED25519:+;}${opensshFingerprintECDSA}" + + cat <> "${ldif_file}" + +dn: ServiceName=openssh,${computer_dn} +ipServiceProtocol: tcp +NagiosEnabled: TRUE +objectClass: EvoService +ipServicePort: 22 +ServiceName: openssh +ServiceType: ssh +ServiceVersion: OpenSSH ${openssh_version} +ServiceFingerprint: ${opensshFingerprint} +EOT +fi + +# NTP +ntp_version=$(get_pkg_version ntp) +if [ -n "${ntp_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=ntp,${computer_dn} +NagiosEnabled: TRUE +objectClass: EvoService +ServiceName: ntp +ServiceType: ntp +ServiceVersion: NTP ${ntp_version} +EOT +fi + +for net in $(ls /sys/class/net); do + path=$(readlink -e /sys/class/net/${net}) + echo $path | grep -q virtual + if [ $? -ne 0 ]; then + hw=$(cat ${path}/address) + vendor_id=$(cat ${path}/device/vendor) + dev_id=$(cat ${path}/device/device) + [ "${dev_id}" = "0x0001" ] && dev_id="0x1000" + dev=$(lspci -d "${vendor_id}:${dev_id}" -vm) + vendor=$(echo "${dev}" | grep -E "^Vendor" | cut -d':' -f2 | xargs) + model=$(echo "${dev}" | grep -E "^Vendor" -A1 | grep -E "^Device" | cut -d':' -f2 | xargs) + size=$(cat ${path}/tx_queue_len) + ips=$(ip -o addr show "${net}" | grep "global" | awk '{print $4 }' | xargs | cut -d'/' -f1) + cat <> "${ldif_file}" + +dn: HardwareName=$net,EvoComputerName=$(hostname),ou=computer,dc=evolix,dc=net +objectClass: EvoHardware +HardwareAddress: ${hw} +EOT + [ -n "$ips" ] && echo "HardwareIP: ${ips}" >> "${ldif_file}" + cat <> "${ldif_file}" +HardwareMark: ${vendor} +HardwareModel: ${model} +HardwareName: ${net} +HardwareSize: ${size} +HardwareType: netcard +EOT + fi +done + +# Apache +if is_pkg_installed apache2-data; then + apache_version=$(get_pkg_version apache2-data) +fi +if [ -n "${apache_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=apache,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: apache +ipServicePort: 80 +ServiceType: http +ServiceVersion: Apache ${apache_version} + +dn: ServiceName=apache-ssl,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: apache-ssl +ipServicePort: 443 +ServiceType: http +ServiceVersion: Apache ${apache_version} +EOT +fi + +# Nginx +if is_pkg_installed nginx-common; then + nginx_version=$(get_pkg_version nginx-common) +fi +if [ -n "${nginx_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=nginx,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: nginx +ipServicePort: 80 +ServiceType: http +ServiceVersion: Nginx ${nginx_version} + +dn: ServiceName=nginx-ssl,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ipServicePort: 443 +ServiceName: nginx-ssl +ServiceType: https +ServiceVersion: Nginx ${nginx_version} +EOT +fi + +# MySQL +if is_pkg_installed mysql-server-5.5; then + mysql_version=$(get_pkg_version mysql-server-5.5) +elif is_pkg_installed mysql-server-5.7; then + mysql_version=$(get_pkg_version mysql-server-5.7) +fi +if [ -n "${mysql_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=mysql,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: mysql +ipServicePort: 3306 +ServiceType: sql +ServiceVersion: MySQL ${mysql_version} +EOT +fi + +# MariaDB +if is_pkg_installed mariadb-server-10.1; then + mariadb_version=$(get_pkg_version mariadb-server-10.1) +elif is_pkg_installed mariadb-server-10.0; then + mariadb_version=$(get_pkg_version mariadb-server-10.0) +fi +if [ -n "${mariadb_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=mysql,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: mysql +ipServicePort: 3306 +ServiceType: sql +ServiceVersion: MariaDB ${mariadb_version} +EOT +fi + +# Squid +if is_pkg_installed squid; then + # squid on Debian 9+ + squid_version=$(get_pkg_version squid) +elif is_pkg_installed squid3-common; then + # squid on Debian 8 + squid_version=$(get_pkg_version squid3-common) +fi +if [ -n "${squid_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=squid,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: squid +ipServicePort: 3128 +ServiceType: proxy +ServiceVersion: Squid ${squid_version} +EOT +fi + +# ProFTPD +if is_pkg_installed proftpd-basic; then + proftpd_version=$(get_pkg_version proftpd-basic) +fi +if [ -n "${proftpd_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=proftpd,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: proftpd +ipServicePort: 3128 +ServiceType: ftp +ServiceVersion: ProFTPD ${proftpd_version} +EOT +fi + +# OpenLDAP +if is_pkg_installed slapd; then + ldap_version=$(get_pkg_version slapd) +fi +if [ -n "${ldap_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=openldap,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: openldap +ipServicePort: 389 +ServiceType: ldap +ServiceVersion: OpenLDAP ${ldap_version} +EOT +fi + +# Dovecot +if is_pkg_installed dovecot-common; then + dovecot_version=$(get_pkg_version dovecot-common) +fi +if [ -n "${dovecot_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=dovecot-pop,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: dovecot-pop +ipServicePort: 110 +ServiceType: pop +ServiceVersion: Dovecot ${dovecot_version} + +dn: ServiceName=dovecot-pop-ssl,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: dovecot-pop-ssl +ipServicePort: 995 +ServiceType: pop +ServiceVersion: Dovecot ${dovecot_version} + +dn: ServiceName=dovecot-imap,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: dovecot-imap +ipServicePort: 143 +ServiceType: imap +ServiceVersion: Dovecot ${dovecot_version} + +dn: ServiceName=dovecot-imap-ssl,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: dovecot-imap-ssl +ipServicePort: 993 +ServiceType: imap +ServiceVersion: Dovecot ${dovecot_version} +EOT +fi + +# Amavis +if is_pkg_installed amavisd-new; then + amavis_version=$(get_pkg_version amavisd-new) +fi +if [ -n "${amavis_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=amavisd-new,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: amavisd-new +ipServicePort: 10024 +ServiceType: smtp +ServiceVersion: amavisd-new ${amavis_version} +EOT +fi + +# ClamAV +if is_pkg_installed clamav-daemon; then + clamav_version=$(get_pkg_version clamav-daemon) +fi +if [ -n "${clamav_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=clamav_db,${computer_dn} +NagiosEnabled: TRUE +objectClass: EvoService +ServiceName: clamav_db +ServiceType: antivirus +ServiceVersion: ClamAV ${clamav_version} +EOT +fi + +# Elasticsearch +if is_pkg_installed elasticsearch; then + elasticsearch_version=$(get_pkg_version elasticsearch) +fi +if [ -n "${elasticsearch_version}" ]; then + cat <> "${ldif_file}" + +dn: ServiceName=elasticsearch,${computer_dn} +NagiosEnabled: TRUE +ipServiceProtocol: tcp +objectClass: EvoService +ServiceName: elasticsearch +ipServicePort: 9200 +ServiceType: http +ServiceVersion: Elasticsearch ${elasticsearch_version} +EOT +fi + +# test if we have a stdout +if [ -t 1 ]; then + echo "Output is in ${ldif_file}" +fi + +exit 0 diff --git a/java8/tasks/main.yml b/java8/tasks/main.yml index 22107bd5..8e24def3 100644 --- a/java8/tasks/main.yml +++ b/java8/tasks/main.yml @@ -11,7 +11,7 @@ - name: Java 8 is installed apt: - name: openjdk-8-jre + name: openjdk-8-jre-headless default_release: "{{ java8_apt_release }}" state: present tags: diff --git a/jenkins/meta/main.yml b/jenkins/meta/main.yml new file mode 100644 index 00000000..eda76a17 --- /dev/null +++ b/jenkins/meta/main.yml @@ -0,0 +1,27 @@ +--- +galaxy_info: + author: Evolix + description: Install Jenkins + + issue_tracker_url: https://forge.evolix.org/projects/ansible-roles/issues + + license: GPLv2 + + min_ansible_version: 2.2 + + platforms: + - name: Debian + versions: + - jessie + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is + # a keyword that describes and categorizes the role. + # Users find roles by searching for tags. Be sure to + # remove the '[]' above if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of + # alphanumeric characters. Maximum 20 tags per role. + +dependencies: + - java8 diff --git a/jenkins/tasks/main.yml b/jenkins/tasks/main.yml index 88db3b90..19496958 100644 --- a/jenkins/tasks/main.yml +++ b/jenkins/tasks/main.yml @@ -1,9 +1,5 @@ --- -- name: Include java8 role - include_role: - name: java8 - - name: Add jenkins GPG key apt_key: # url: https://jenkins-ci.org/debian/jenkins-ci.org.key diff --git a/kibana/README.md b/kibana/README.md index 5d95b5a7..7239adf7 100644 --- a/kibana/README.md +++ b/kibana/README.md @@ -8,6 +8,8 @@ Everything is in the `tasks/main.yml` file. ## Available variables +* `kibana_server_host` : Specifies the address to which the Kibana server will bind (default: `127.0.0.1`) ; +* `kibana_server_basepath` : where to mount the application (default: empty) ; * `kibana_proxy_nginx` : configure an Nginx proxy (not enabled) for Kibana (default: `False`) ; * `kibana_proxy_domain` : domain to use for the proxy ; * `kibana_proxy_ssl_cert` : certificate to use for the proxy ; diff --git a/kibana/defaults/main.yml b/kibana/defaults/main.yml index 7e7555f1..6fd7e16f 100644 --- a/kibana/defaults/main.yml +++ b/kibana/defaults/main.yml @@ -1,4 +1,8 @@ --- + +kibana_server_host: "127.0.0.1" +kibana_server_basepath: "" + kibana_proxy_nginx: False kibana_proxy_domain: "kibana.{{ ansible_fqdn }}" diff --git a/kibana/meta/main.yml b/kibana/meta/main.yml index d0e7a891..dce2560a 100644 --- a/kibana/meta/main.yml +++ b/kibana/meta/main.yml @@ -12,6 +12,7 @@ galaxy_info: - name: Debian versions: - jessie + - stretch dependencies: [] # List your role dependencies here, one per line. diff --git a/kibana/tasks/main.yml b/kibana/tasks/main.yml index 9cf74638..6803568a 100644 --- a/kibana/tasks/main.yml +++ b/kibana/tasks/main.yml @@ -1,9 +1,5 @@ --- -- name: Install java8 - include_role: - name: java8 - - name: APT https transport is enabled apt: name: apt-transport-https @@ -24,7 +20,7 @@ - name: Elastic sources list is available apt_repository: repo: "deb https://artifacts.elastic.co/packages/5.x/apt stable main" - filename: elastic.list + filename: elastic state: present update_cache: yes tags: @@ -38,8 +34,24 @@ tags: - packages +- name: kibana server host configuration + lineinfile: + dest: /etc/kibana/kibana.yml + line: "server.host: \"{{ kibana_server_host }}\"" + regexp: '^server.host:' + insertafter: '^#server.host:' + notify: restart kibana + +- name: kibana server basepath configuration + lineinfile: + dest: /etc/kibana/kibana.yml + line: "server.basePath: \"{{ kibana_server_basepath }}\"" + regexp: '^server.basePath:' + insertafter: '^#server.basePath:' + notify: restart kibana + - name: Kibana service is enabled and started - service: + systemd: name: kibana enabled: yes state: started @@ -62,22 +74,17 @@ when: not ansible_check_mode - block: - - name: Remount /usr as writable - command: "mount -o remount,rw /usr" - args: - warn: no + - include_role: + name: remount-usr - name: Move kibana optimize directory - shell: "mv /usr/share/kibana/optimize /var/lib/kibana/optimize && ln -s /var/lib/kibana/optimize /usr/share/kibana/optimize" + shell: "mv /usr/share/kibana/{{ item }} /var/lib/kibana/{{ item }} && ln -s /var/lib/kibana/{{ item }} /usr/share/kibana/{{ item }}" args: - creates: /var/lib/kibana/optimize + creates: "/var/lib/kibana/{{ item }}" notify: restart kibana - - - name: Remount /usr as read-only - command: "mount -o remount /usr" - args: - warn: no - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") + with_items: + - optimize + - data - include: proxy_nginx.yml when: kibana_proxy_nginx diff --git a/kibana/tasks/remount_usr_rw.yml b/kibana/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/kibana/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/kibana/templates/nginx_proxy_kibana_nossl.j2 b/kibana/templates/nginx_proxy_kibana_nossl.j2 index 1540b841..3c674317 100644 --- a/kibana/templates/nginx_proxy_kibana_nossl.j2 +++ b/kibana/templates/nginx_proxy_kibana_nossl.j2 @@ -9,7 +9,7 @@ server { server_name {{ kibana_proxy_domain }}; # Auth. - include /etc/nginx/snippets/private_ipaddr_whitelist; + include /etc/nginx/snippets/ipaddr_whitelist; deny all; auth_basic "Reserved {{ kibana_proxy_domain }}"; auth_basic_user_file /etc/nginx/snippets/private_htpasswd; diff --git a/kibana/templates/nginx_proxy_kibana_ssl.j2 b/kibana/templates/nginx_proxy_kibana_ssl.j2 index ea2e06c9..c72db251 100644 --- a/kibana/templates/nginx_proxy_kibana_ssl.j2 +++ b/kibana/templates/nginx_proxy_kibana_ssl.j2 @@ -19,7 +19,7 @@ server { ssl_certificate_key {{ kibana_proxy_ssl_key }}; # Auth. - include /etc/nginx/snippets/private_ipaddr_whitelist; + include /etc/nginx/snippets/ipaddr_whitelist; deny all; auth_basic "Reserved {{ kibana_proxy_domain }}"; auth_basic_user_file /etc/nginx/snippets/private_htpasswd; diff --git a/kvm-host/tasks/main.yml b/kvm-host/tasks/main.yml index a3ee3556..9fc73e93 100644 --- a/kvm-host/tasks/main.yml +++ b/kvm-host/tasks/main.yml @@ -5,21 +5,14 @@ - include: packages.yml -- name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - check_mode: no - register: usr_partition +- include_role: + name: remount-usr -- name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 +- name: Copy add-vm script + get_url: + url: https://forge.evolix.org/projects/kvm-tools/repository/revisions/master/raw/add-vm.sh + dest: /usr/share/scripts/add-vm.sh + mode: "0750" - include: munin.yml diff --git a/ldap/defaults/main.yml b/ldap/defaults/main.yml index 1e90583f..88631a11 100644 --- a/ldap/defaults/main.yml +++ b/ldap/defaults/main.yml @@ -1,4 +1,4 @@ --- -ldap_domain: "{{ ansible_fqdn }}" -ldap_organization: "{{ ansible_domain }}" -#ldap_password=$(apg -n1 -m 12 -c cl_seed) +ldap_hostname: "{{ ansible_hostname }}" +ldap_domain: "{{ ansible_domain }}" +ldap_suffix: "dc={{ ldap_hostname }},dc={{ ldap_domain.split('.')[-2] }},dc={{ ldap_domain.split('.')[-1] }}" diff --git a/ldap/tasks/main.yml b/ldap/tasks/main.yml index c28c01fe..84bed58d 100644 --- a/ldap/tasks/main.yml +++ b/ldap/tasks/main.yml @@ -6,8 +6,82 @@ - slapd - ldap-utils - ldapvi + - shelldap + +- name: "Is /root/.ldapvirc present ?" + stat: + path: /root/.ldapvirc + check_mode: no + register: root_ldapvirc_path - name: apg package is installed apt: name: apg state: present + when: not root_ldapvirc_path.stat.exists + +- name: create a password for cn=admin + command: "apg -n 1 -m 16 -M lcN" + register: ldap_admin_password + changed_when: False + when: not root_ldapvirc_path.stat.exists + +- name: create a password for cn=nagios + command: "apg -n 1 -m 16 -M lcN" + register: ldap_nagios_password + changed_when: False + when: not root_ldapvirc_path.stat.exists + +- name: hash password for cn=admin + command: "slappasswd -s {{ ldap_admin_password.stdout }}" + register: ldap_admin_password_ssha + changed_when: False + when: not root_ldapvirc_path.stat.exists + +- name: hash password for cn=nagios + command: "slappasswd -s {{ ldap_nagios_password.stdout }}" + register: ldap_nagios_password_ssha + changed_when: False + when: not root_ldapvirc_path.stat.exists + +- name: create ldapvirc config + template: + src: ldapvirc.j2 + dest: /root/.ldapvirc + mode: "0640" + when: not root_ldapvirc_path.stat.exists + +- name: upload ldap initial config + template: + src: config_ldapvi.j2 + dest: /root/evolinux_ldap_config.ldapvi + mode: "0640" + when: not root_ldapvirc_path.stat.exists + +- name: upload ldap initial entries + template: + src: first-entries.ldif.j2 + dest: /root/evolinux_ldap_first-entries.ldif + mode: "0640" + when: not root_ldapvirc_path.stat.exists + +- name: inject config + command: ldapvi -Y EXTERNAL -h ldapi:// --ldapmodify /root/evolinux_ldap_config.ldapvi + environment: + TERM: xterm + when: not root_ldapvirc_path.stat.exists + +- name: inject first entries + command: slapadd -l /root/evolinux_ldap_first-entries.ldif + when: not root_ldapvirc_path.stat.exists + +- name: upload custom schema + copy: + src: "{{ ldap_schema }}" + dest: "/root/{{ ldap_schema }}" + mode: "0640" + when: not root_ldapvirc_path.stat.exists and ldap_schema is defined + +- name: inject custom schema + command: "ldapadd -Y EXTERNAL -H ldapi:/// -f /root/{{ ldap_schema }}" + when: not root_ldapvirc_path.stat.exists and ldap_schema is defined diff --git a/ldap/templates/config_ldapvi.j2 b/ldap/templates/config_ldapvi.j2 new file mode 100644 index 00000000..9be8044c --- /dev/null +++ b/ldap/templates/config_ldapvi.j2 @@ -0,0 +1,8 @@ +modify: olcDatabase={1}mdb,cn=config +olcSuffix: {{ ldap_suffix }} +olcRootDN: cn=admin,{{ ldap_suffix }} +olcRootPW: {{ ldap_admin_password_ssha.stdout }} +olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break +olcAccess: {1}to attrs=userPassword by self write by anonymous auth by dn="cn=admin,{{ ldap_suffix }}" write by dn="cn=perl,ou=ldapusers,{{ ldap_suffix }}" write by * none +olcAccess: {2}to attrs=shadowLastChange by self write by dn="cn=admin,{{ ldap_suffix }}" write by dn="cn=perl,ou=ldapusers,{{ ldap_suffix }}" write by * read +olcAccess: {3}to * by self write by dn="cn=admin,{{ ldap_suffix }}" write by dn="cn=perl,ou=ldapusers,{{ ldap_suffix }}" write by * read diff --git a/ldap/templates/first-entries.ldif.j2 b/ldap/templates/first-entries.ldif.j2 new file mode 100644 index 00000000..0e82ddbc --- /dev/null +++ b/ldap/templates/first-entries.ldif.j2 @@ -0,0 +1,30 @@ +dn: {{ ldap_suffix }} +objectClass: top +objectClass: dcObject +objectClass: organization +o: {{ ldap_domain }} +dc: {{ ldap_hostname }} + +dn: cn=admin,{{ ldap_suffix }} +objectClass: simpleSecurityObject +objectClass: organizationalRole +cn: admin +description: LDAP administrator +userPassword: {{ ldap_admin_password_ssha.stdout }} + +dn: ou=ldapusers,{{ ldap_suffix }} +objectClass: top +objectClass: organizationalUnit +ou: ldapusers + +dn: cn=perl,ou=ldapusers,{{ ldap_suffix }} +objectClass: simpleSecurityObject +objectClass: organizationalRole +cn: perl +userPassword: {{ ldap_admin_password_ssha.stdout }} + +dn: cn=nagios,ou=ldapusers,{{ ldap_suffix }} +objectClass: simpleSecurityObject +objectClass: organizationalRole +cn: nagios +userPassword: {{ ldap_nagios_password_ssha.stdout }} diff --git a/ldap/templates/ldapvirc.j2 b/ldap/templates/ldapvirc.j2 new file mode 100644 index 00000000..e61a7524 --- /dev/null +++ b/ldap/templates/ldapvirc.j2 @@ -0,0 +1,6 @@ +profile default +host: ldap://127.0.0.1 +base: {{ ldap_suffix }} +user: cn=admin,{{ ldap_suffix }} +bind: simple +password: {{ ldap_admin_password.stdout }} diff --git a/listupgrade/tasks/main.yml b/listupgrade/tasks/main.yml index 74944eca..de9fdb2c 100644 --- a/listupgrade/tasks/main.yml +++ b/listupgrade/tasks/main.yml @@ -22,7 +22,7 @@ state: directory owner: root group: root - mode: "0600" + mode: "0700" - name: Copy listupgrade config template: diff --git a/logstash/defaults/main.yml b/logstash/defaults/main.yml index 2d3c7b40..e563f517 100644 --- a/logstash/defaults/main.yml +++ b/logstash/defaults/main.yml @@ -1,3 +1,4 @@ --- logstash_jvm_xms: 256m logstash_jvm_xmx: 1g +logstash_log_rotate_days: 365 diff --git a/logstash/meta/main.yml b/logstash/meta/main.yml index 629e9f67..c74021e7 100644 --- a/logstash/meta/main.yml +++ b/logstash/meta/main.yml @@ -13,7 +13,5 @@ galaxy_info: versions: - jessie -dependencies: [] - # List your role dependencies here, one per line. - # Be sure to remove the '[]' above if you add dependencies - # to this list. +dependencies: + - java8 diff --git a/logstash/tasks/logs.yml b/logstash/tasks/logs.yml new file mode 100644 index 00000000..9d5b5023 --- /dev/null +++ b/logstash/tasks/logs.yml @@ -0,0 +1,9 @@ +--- + +- name: "log rotation script" + template: + src: rotate_logstash_logs.j2 + dest: /etc/cron.daily/rotate_logstash_logs + owner: root + group: root + mode: "0750" diff --git a/logstash/tasks/main.yml b/logstash/tasks/main.yml index 16e9ae79..71be5614 100644 --- a/logstash/tasks/main.yml +++ b/logstash/tasks/main.yml @@ -1,11 +1,5 @@ --- -- name: Install java8 - include_role: - name: java8 - tags: - - packages - - name: APT https transport is enabled apt: name: apt-transport-https @@ -26,7 +20,7 @@ - name: Elastic sources list is available apt_repository: repo: "deb https://artifacts.elastic.co/packages/5.x/apt stable main" - filename: elastic.list + filename: elastic state: present update_cache: yes tags: @@ -41,7 +35,7 @@ - packages - name: Logstash service is enabled - service: + systemd: name: logstash enabled: yes @@ -76,3 +70,5 @@ - debug: var: logstash_template verbosity: 1 + +- include: logs.yml diff --git a/logstash/templates/rotate_logstash_logs.j2 b/logstash/templates/rotate_logstash_logs.j2 new file mode 100644 index 00000000..40155506 --- /dev/null +++ b/logstash/templates/rotate_logstash_logs.j2 @@ -0,0 +1,9 @@ +#!/bin/sh +# {{ ansible_managed }} + +LOG_DIR=/var/log/logstash +MAX_AGE={{ logstash_log_rotate_days | mandatory }} + +find ${LOG_DIR} -type f -user logstash -name "logstash.log.*.gz" -mtime +${MAX_AGE} -delete +find ${LOG_DIR} -type f -user root -name "logstash.err.*.gz" -mtime +${MAX_AGE} -delete +find ${LOG_DIR} -type f -user root -name "logstash.stdout.*.gz" -mtime +${MAX_AGE} -delete diff --git a/memcached/README.md b/memcached/README.md index 3c571029..38e5f89d 100644 --- a/memcached/README.md +++ b/memcached/README.md @@ -1,4 +1,4 @@ -# PHP-FPM +# Memcached Installation and basic configuration of memcached diff --git a/meta/main.yml b/meta/main.yml new file mode 100644 index 00000000..b32a44cf --- /dev/null +++ b/meta/main.yml @@ -0,0 +1,2 @@ +--- +galaxy_info: diff --git a/minifirewall/defaults/main.yml b/minifirewall/defaults/main.yml index 69e1e8fe..4c8498cf 100644 --- a/minifirewall/defaults/main.yml +++ b/minifirewall/defaults/main.yml @@ -6,16 +6,23 @@ minifirewall_checkout_path: "/tmp/minifirewall" minifirewall_int: "{{ ansible_default_ipv4.interface }}" minifirewall_ipv6: "on" minifirewall_intlan: "{{ ansible_default_ipv4.address }}/32" -minifirewall_trusted_ips: ["0.0.0.0/0"] + +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +# and default to ['0.0.0.0/0'] if the result is still empty +minifirewall_trusted_ips: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique | default(['0.0.0.0/0'], true) }}" minifirewall_privilegied_ips: [] minifirewall_protected_ports_tcp: [22] minifirewall_protected_ports_udp: [] -minifirewall_public_ports_tcp: [22, 80, 443] -minifirewall_public_ports_udp: [] -minifirewall_semipublic_ports_tcp: [20, 21, 25] +minifirewall_public_ports_tcp: [25, 53, 443, 993, 995, 2222] +minifirewall_public_ports_udp: [53] +minifirewall_semipublic_ports_tcp: [20, 21, 22, 80, 110, 143] minifirewall_semipublic_ports_udp: [] minifirewall_private_ports_tcp: [5666] minifirewall_private_ports_udp: [] minifirewall_autostart: "no" + +evomaintenance_hosts: [] diff --git a/minifirewall/tasks/config.yml b/minifirewall/tasks/config.yml index 80acf5d0..ea6b1a9e 100644 --- a/minifirewall/tasks/config.yml +++ b/minifirewall/tasks/config.yml @@ -94,6 +94,20 @@ SERVICESUDP3='{{ minifirewall_private_ports_udp | join(' ') }}' register: minifirewall_config_ports +- name: evomaintenance + lineinfile: + dest: /etc/default/minifirewall + line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT" + insertafter: "^# EvoMaintenance" + with_items: "{{ evomaintenance_hosts }}" + +- name: remove minifirewall example rule for the evomaintenance + lineinfile: + dest: /etc/default/minifirewall + regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)' + state: absent + when: evomaintenance_hosts != [] + - name: restart minifirewall # service: # name: minifirewall diff --git a/minifirewall/tasks/install.yml b/minifirewall/tasks/install.yml index 47d72b44..5efdd585 100644 --- a/minifirewall/tasks/install.yml +++ b/minifirewall/tasks/install.yml @@ -1,5 +1,12 @@ --- +- name: dependencies are satisfied + apt: + name: '{{ item }}' + state: present + with_items: + - iptables + - name: init script is copied copy: src: minifirewall diff --git a/minifirewall/tasks/main.yml b/minifirewall/tasks/main.yml index 0208313a..851d1917 100644 --- a/minifirewall/tasks/main.yml +++ b/minifirewall/tasks/main.yml @@ -1,12 +1,5 @@ --- -- name: packages are installed - apt: - name: '{{ item }}' - state: present - with_items: - - iptables - - include: install.yml - include: config.yml diff --git a/mysql/tasks/munin.yml b/mysql/tasks/munin.yml index 0903def1..52b6eed4 100644 --- a/mysql/tasks/munin.yml +++ b/mysql/tasks/munin.yml @@ -36,18 +36,25 @@ dest: '/etc/munin/plugins/mysql_{{ item }}' state: link with_items: + - commands - connections - files_tables - innodb_bpool - innodb_bpool_act + - innodb_insert_buf - innodb_io + - innodb_io_pend - innodb_log - innodb_rows - innodb_semaphores - myisam_indexes + - network_traffic - qcache - qcache_mem + - select_types + - slow - sorts + - table_locks - tmp_tables notify: restart munin-node diff --git a/mysql/tasks/remount_usr_rw.yml b/mysql/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/mysql/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/mysql/tasks/users_jessie.yml b/mysql/tasks/users_jessie.yml index a8c22cf8..e1a02130 100644 --- a/mysql/tasks/users_jessie.yml +++ b/mysql/tasks/users_jessie.yml @@ -13,6 +13,7 @@ command: "apg -n 1 -m 16 -M lcN" register: mysql_admin_password changed_when: False + check_mode: no tags: - mysql diff --git a/mysql/tasks/utils.yml b/mysql/tasks/utils.yml index d0fe71a8..a6fc307c 100644 --- a/mysql/tasks/utils.yml +++ b/mysql/tasks/utils.yml @@ -30,9 +30,10 @@ when: ansible_distribution_major_version | version_compare('9', '>=') - name: Read debian-sys-maint password - shell: cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3 + shell: 'cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3' register: mysql_debian_password changed_when: False + check_mode: no tags: - mysql @@ -48,7 +49,8 @@ # mysqltuner -- include: remount_usr_rw.yml +- include_role: + name: remount-usr when: (mysql_scripts_dir or general_scripts_dir) | search ("/usr") - name: Install mysqltuner @@ -71,7 +73,8 @@ # automatic optimizations -- include: remount_usr_rw.yml +- include_role: + name: remount-usr when: (mysql_scripts_dir or general_scripts_dir) | search ("/usr") - name: Optimize script for MySQL @@ -133,7 +136,8 @@ # my-add.sh -- include: remount_usr_rw.yml +- include_role: + name: remount-usr when: (mysql_scripts_dir or general_scripts_dir) | search ("/usr") - name: Install my-add.sh diff --git a/nagios-nrpe/defaults/main.yml b/nagios-nrpe/defaults/main.yml index c9ee2603..96c3ddd3 100644 --- a/nagios-nrpe/defaults/main.yml +++ b/nagios-nrpe/defaults/main.yml @@ -1,5 +1,8 @@ --- -nagios_nrpe_allowed_hosts: [] +evolix_trusted_ips: [] +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_ldap_dc: "dc=DOMAIN,dc=EXT" nagios_nrpe_ldap_passwd: LDAP_PASSWD nagios_nrpe_pgsql_passwd: PGSQL_PASSWD diff --git a/nagios-nrpe/files/plugins/check_amavis b/nagios-nrpe/files/plugins/check_amavis index 43e69bcb..d364dba3 100755 --- a/nagios-nrpe/files/plugins/check_amavis +++ b/nagios-nrpe/files/plugins/check_amavis @@ -3,12 +3,14 @@ use Getopt::Long; use MIME::Entity; use Net::SMTP; +use POSIX qw(strftime); my $server = ''; my $port = 10024; my $from = ''; my $to = ''; my $debug = 0; +my $date = strftime "%a, %d %b %g %X %z", localtime; $result = GetOptions ( "server|s=s" => \$server, @@ -32,6 +34,7 @@ my $top = MIME::Entity->build( Type =>"multipart/mixed", From => $from, To => $to, + Date => $date, Subject => "EICAR test", Data => "This is a test", ); @@ -62,7 +65,7 @@ $smtp->close(); print "$result\n"; -if ($result =~/2.7.0 Ok, discarded/) { +if ($result =~/2.5.0 Ok, id=[^,]+, BOUNCE/) { print "OK - All fine\n"; exit 0; } else { diff --git a/nagios-nrpe/files/plugins_bsd/check_free_mem.sh b/nagios-nrpe/files/plugins_bsd/check_free_mem.sh index f2261ea9..f0b79c8a 100755 --- a/nagios-nrpe/files/plugins_bsd/check_free_mem.sh +++ b/nagios-nrpe/files/plugins_bsd/check_free_mem.sh @@ -64,7 +64,7 @@ __EOT # Total memory size (in MB) tot_mem=$(( `/sbin/sysctl -n hw.physmem` / BYTES_IN_MB)) # Free memory size (in MB) -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 $4 }' | tr -d 'M') # Free memory size (in percentage) free_mem_perc=$(( free_mem * 100 / tot_mem )) diff --git a/nagios-nrpe/tasks/main.yml b/nagios-nrpe/tasks/main.yml index dbb73903..d0298c6c 100644 --- a/nagios-nrpe/tasks/main.yml +++ b/nagios-nrpe/tasks/main.yml @@ -17,6 +17,7 @@ dest: /etc/nagios/nrpe.d/evolix.cfg group: nagios mode: "0640" + force: no notify: restart nagios-nrpe-server - name: Nagios config is secured @@ -27,7 +28,8 @@ state: directory notify: restart nagios-nrpe-server -- include: remount_usr_rw.yml +- include_role: + name: remount-usr when: nagios_plugins_directory | search ("/usr") tags: - nagios-plugins diff --git a/nagios-nrpe/tasks/remount_usr_rw.yml b/nagios-nrpe/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/nagios-nrpe/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index 45223167..38e29b27 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -28,6 +28,7 @@ command[check_ldap]=/usr/lib/nagios/plugins/check_ldap -3 -H localhost -D cn=nag command[check_ldaps]=/usr/lib/nagios/plugins/check_ldaps -3 -H localhost -b {{ nagios_nrpe_ldap_dc }} command[check_imap]=/usr/lib/nagios/plugins/check_imap -H localhost command[check_imaps]=/usr/lib/nagios/plugins/check_imap -S -H localhost -p 993 +command[check_imapproxy]=/usr/lib/nagios/plugins/check_imap -H localhost -p 1143 command[check_pop]=/usr/lib/nagios/plugins/check_pop -H localhost command[check_pops]=/usr/lib/nagios/plugins/check_pop -S -H localhost -p 995 command[check_ftp]=/usr/lib/nagios/plugins/check_ftp -H localhost @@ -48,6 +49,7 @@ command[check_clamav_db]=/usr/lib/nagios/plugins/check_file_age -w 86400 -c 1728 command[check_ssl]=/usr/lib/nagios/plugins/check_http -f follow -I 127.0.0.1 -S -p 443 -H ssl.evolix.net -C 15,5 command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex command[check_memcached]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 11211 +command[check_opendkim]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 54321 # Local checks (not packaged) command[check_mem]={{ nagios_plugins_directory }}/check_mem -f -C -w 20 -c 10 diff --git a/nginx/README.md b/nginx/README.md index d519608b..73ede527 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -18,8 +18,8 @@ Main variables are : * `nginx_minimal` : very basic install and config (default: `False`) ; * `nginx_jessie_backports` : on Debian Jessie, we can prefer v1.10 from backports (default: `False`) ; -* `nginx_private_ipaddr_whitelist_present` : list of IP addresses to have in the private whitelist ; -* `nginx_private_ipaddr_whitelist_absent` : list of IP addresses **not** to have in the whitelist ; +* `nginx_ipaddr_whitelist_present` : list of IP addresses to have in the private whitelist ; +* `nginx_ipaddr_whitelist_absent` : list of IP addresses **not** to have in the whitelist ; * `nginx_private_htpasswd_present` : list of users to have in the private htpasswd ; * `nginx_private_htpasswd_absent` : list of users to **not** have in the private htpasswd. diff --git a/nginx/defaults/main.yml b/nginx/defaults/main.yml index 16398ee4..38dcbb89 100644 --- a/nginx/defaults/main.yml +++ b/nginx/defaults/main.yml @@ -3,8 +3,11 @@ nginx_minimal: False nginx_jessie_backports: False -nginx_private_ipaddr_whitelist_present: [] -nginx_private_ipaddr_whitelist_absent: [] +evolix_trusted_ips: [] +additional_trusted_ips: [] +# Let's merge evolix_trusted_ips with additional_trusted_ips +nginx_ipaddr_whitelist_present: "{{ evolix_trusted_ips | union(additional_trusted_ips) | unique }}" +nginx_ipaddr_whitelist_absent: [] nginx_private_htpasswd_present: [] nginx_private_htpasswd_absent: [] diff --git a/nginx/files/nginx/snippets/private_ipaddr_whitelist b/nginx/files/nginx/snippets/ipaddr_whitelist similarity index 100% rename from nginx/files/nginx/snippets/private_ipaddr_whitelist rename to nginx/files/nginx/snippets/ipaddr_whitelist diff --git a/nginx/tasks/main_regular.yml b/nginx/tasks/main_regular.yml index 74580972..f6563b76 100644 --- a/nginx/tasks/main_regular.yml +++ b/nginx/tasks/main_regular.yml @@ -38,13 +38,13 @@ - nginx # TODO: verify that those permissions are correct : -# not too strict for private_ipaddr_whitelist +# not too strict for ipaddr_whitelist # and not too loose for private_htpasswd -- name: Copy private_ipaddr_whitelist +- name: Copy ipaddr_whitelist copy: - src: nginx/snippets/private_ipaddr_whitelist - dest: /etc/nginx/snippets/private_ipaddr_whitelist + src: nginx/snippets/ipaddr_whitelist + dest: /etc/nginx/snippets/ipaddr_whitelist owner: www-data group: www-data directory_mode: "0640" @@ -56,20 +56,20 @@ - name: add IP addresses to private IP whitelist lineinfile: - dest: /etc/nginx/snippets/private_ipaddr_whitelist + dest: /etc/nginx/snippets/ipaddr_whitelist line: "allow {{ item }};" state: present - with_items: "{{ nginx_private_ipaddr_whitelist_present }}" + with_items: "{{ nginx_ipaddr_whitelist_present }}" notify: reload nginx tags: - nginx - name: remove IP addresses from private IP whitelist lineinfile: - dest: /etc/nginx/snippets/private_ipaddr_whitelist + dest: /etc/nginx/snippets/ipaddr_whitelist line: "allow {{ item }};" state: absent - with_items: "{{ nginx_private_ipaddr_whitelist_absent }}" + with_items: "{{ nginx_ipaddr_whitelist_absent }}" notify: reload nginx tags: - nginx @@ -112,6 +112,7 @@ src: evolinux-default.conf.j2 dest: /etc/nginx/sites-available/evolinux-default.conf mode: "0640" + force: no notify: reload nginx tags: - nginx diff --git a/nginx/templates/evolinux-default.conf.j2 b/nginx/templates/evolinux-default.conf.j2 index 165f39f8..cc2d7f46 100644 --- a/nginx/templates/evolinux-default.conf.j2 +++ b/nginx/templates/evolinux-default.conf.j2 @@ -23,8 +23,7 @@ server { root /var/www; # Auth. - include /etc/nginx/snippets/private_ipaddr_whitelist; - deny all; + include /etc/nginx/snippets/ipaddr_whitelist; auth_basic "Reserved {{ ansible_fqdn }}"; auth_basic_user_file /etc/nginx/snippets/private_htpasswd; satisfy any; diff --git a/opendkim/files/opendkim-add.sh b/opendkim/files/opendkim-add.sh new file mode 100644 index 00000000..a7da1ce0 --- /dev/null +++ b/opendkim/files/opendkim-add.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ "$#" -ne 1 ]; then + echo "Usage : $0 example.com" >&2 + exit 1 +fi + +domain="$(echo "$1"|xargs)" + +mkdir -pm 0750 "/etc/opendkim/keys/${domain}" +chown opendkim:opendkim "/etc/opendkim/keys/${domain}" + +if [ ! -f "/etc/opendkim/keys/${domain}/default.private" ]; then + cd "/etc/opendkim/keys/${domain}" + echo "Generate DKIM keys ..." + sudo -u opendkim opendkim-genkey -r -d "${domain}" + chmod 640 /etc/opendkim/keys/${domain}/* +fi + +grep -q "${domain}" /etc/opendkim/TrustedHosts +if [ "$?" -ne 0 ]; then + echo "Add ${domain} to TrustedHosts ..." + echo "${domain}" >> /etc/opendkim/TrustedHosts +fi + +grep -q "${domain}" /etc/opendkim/KeyTable +if [ "$?" -ne 0 ]; then + echo "Add ${domain} to KeyTable ..." + echo "default._domainkey.${domain} ${domain}:default:/etc/opendkim/keys/${domain}/default.private" >> /etc/opendkim/KeyTable +fi + +grep -q "${domain}" /etc/opendkim/SigningTable +if [ "$?" -ne 0 ]; then + echo "Add ${domain} to SigningTable ..." + echo "*@${domain} default._domainkey.${domain}" >> /etc/opendkim/SigningTable +fi + +systemctl reload opendkim +if [ "$?" -eq 0 ]; then + echo "OpenDKIM successfully reloaded" + echo "Public key is in : /etc/opendkim/keys/${domain}/default.txt" + exit 0 +else + echo "An error has occurred while opendkim reload, please FIX configuration !" >&2 + exit 1 +fi diff --git a/opendkim/files/opendkim.conf b/opendkim/files/opendkim.conf new file mode 100644 index 00000000..c8c4d385 --- /dev/null +++ b/opendkim/files/opendkim.conf @@ -0,0 +1,18 @@ +UserID opendkim:opendkim +Socket inet:54321@127.0.0.1 +PidFile /var/run/opendkim/opendkim.pid +OversignHeaders From +TrustAnchorFile /usr/share/dns/root.key +Selector default +Canonicalization relaxed/relaxed +ExternalIgnoreList refile:/etc/opendkim/TrustedHosts +InternalHosts refile:/etc/opendkim/TrustedHosts +KeyTable refile:/etc/opendkim/KeyTable +LogResults Yes +LogWhy Yes +Mode sv +SigningTable refile:/etc/opendkim/SigningTable +Syslog Yes +SyslogSuccess Yes +TemporaryDirectory /var/tmp +UMask 007 diff --git a/opendkim/handlers/main.yml b/opendkim/handlers/main.yml new file mode 100644 index 00000000..ccf166a8 --- /dev/null +++ b/opendkim/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: reload opendkim + systemd: + name: opendkim + state: reloaded + +- name: restart opendkim + systemd: + name: opendkim + state: restarted diff --git a/opendkim/tasks/main.yml b/opendkim/tasks/main.yml new file mode 100644 index 00000000..8c81b686 --- /dev/null +++ b/opendkim/tasks/main.yml @@ -0,0 +1,78 @@ +--- +- name: install OpenDKIM + apt: + name: "{{ item }}" + state: present + with_items: + - opendkim + - opendkim-tools + tags: + - opendkim + +- name: create keys directory + file: + name: "{{ item }}" + state: directory + owner: opendkim + group: opendkim + mode: "0750" + with_items: + - '/etc/opendkim' + - '/etc/opendkim/keys' + tags: + - opendkim + +- name: add 127.0.0.1 to TrustedHosts + lineinfile: + dest: '/etc/opendkim/TrustedHosts' + line: '127.0.0.1' + create: True + owner: opendkim + group: opendkim + mode: "0640" + notify: reload opendkim + tags: + - opendkim + +- name: create config files + file: + name: "/etc/opendkim/{{ item }}" + state: touch + owner: opendkim + group: opendkim + mode: "0640" + with_items: + - 'KeyTable' + - 'SigningTable' + changed_when: False + tags: + - opendkim + +- name: copy OpenDKIM config + copy: + src: opendkim.conf + dest: /etc/opendkim.conf + mode: "0644" + force: yes + notify: restart opendkim + tags: + - opendkim + +- name: ensure opendkim is started and enabled + systemd: + name: opendkim + state: started + enabled: True + tags: + - opendkim + +- include_role: + name: remount-usr + +- name: deploy opendkim-add.sh script + copy: + src: opendkim-add.sh + dest: /usr/share/scripts/opendkim-add.sh + mode: "0750" + tags: + - opendkim diff --git a/packweb-apache/README.md b/packweb-apache/README.md index d3f3f5b6..99e25da1 100644 --- a/packweb-apache/README.md +++ b/packweb-apache/README.md @@ -4,7 +4,7 @@ Install the web pack, with Apache. ## Tasks -Everything is in the `tasks/main.yml` file for now. +See `tasks/main.yml`. ## Available variables diff --git a/packweb-apache/meta/main.yml b/packweb-apache/meta/main.yml new file mode 100644 index 00000000..914dbebb --- /dev/null +++ b/packweb-apache/meta/main.yml @@ -0,0 +1,19 @@ +galaxy_info: + author: Evolix + description: Installation of Evolix "Pack Web" meta-role + + issue_tracker_url: https://forge.evolix.org/projects/ansible-roles/issues + + license: GPLv2 + + min_ansible_version: 2.2 + + platforms: + - name: Debian + versions: + - jessie + - stretch + +dependencies: + - { role: squid, squid_localproxy_enable: True } + - mysql diff --git a/packweb-apache/tasks/awstats.yml b/packweb-apache/tasks/awstats.yml index 1919b17d..5ea0fa57 100644 --- a/packweb-apache/tasks/awstats.yml +++ b/packweb-apache/tasks/awstats.yml @@ -46,3 +46,11 @@ create: yes regexp: '-config=awstats' line: "10 */6 * * * root umask 033; [ -x /usr/lib/cgi-bin/awstats.pl -a -f /etc/awstats/awstats.conf -a -r /var/log/apache2/access.log ] && /usr/lib/cgi-bin/awstats.pl -config=awstats -update >/dev/null" + +- name: Comment default awstat cron's tasks + lineinfile: + dest: /etc/cron.d/awstats + regexp: "(?i)^([^#]*update\\.sh.*)" + line: '#\1' + backrefs: yes + state: present diff --git a/php/defaults/main.yml b/php/defaults/main.yml index ca243024..d12014b2 100644 --- a/php/defaults/main.yml +++ b/php/defaults/main.yml @@ -1,5 +1,6 @@ --- +php_sury_enable: False php_fpm_enable: False php_apache_enable: False php_symfony_requirements: False diff --git a/php/files/sury.preferences b/php/files/sury.preferences new file mode 100644 index 00000000..9c644b5d --- /dev/null +++ b/php/files/sury.preferences @@ -0,0 +1,7 @@ +Package: php* libapache2-mod-php* +Pin: origin packages.sury.org +Pin-Priority: 999 + +Package: * +Pin: origin packages.sury.org +Pin-Priority: 50 diff --git a/php/tasks/apache.yml b/php/tasks/apache.yml index df352848..cefeb95c 100644 --- a/php/tasks/apache.yml +++ b/php/tasks/apache.yml @@ -52,6 +52,7 @@ section: PHP option: disable_functions value: "exec,shell-exec,system,passthru,putenv,popen" + mode: "0644" - name: Custom php.ini copy: @@ -59,6 +60,7 @@ content: | ; Put customized values here. ; default_charset = "ISO-8859-1" + mode: "0644" force: no - name: "Set custom values for PHP to enable Symfony" diff --git a/php/tasks/main.yml b/php/tasks/main.yml index 7ea4269c..9b1d3375 100644 --- a/php/tasks/main.yml +++ b/php/tasks/main.yml @@ -8,6 +8,9 @@ - include: php_jessie.yml when: ansible_distribution_release == "jessie" +- include: php_stretch_sury.yml + when: ansible_distribution_major_version | version_compare('9', '>=') and php_sury_enable + - include: php_stretch.yml when: ansible_distribution_major_version | version_compare('9', '>=') diff --git a/php/tasks/php_stretch_sury.yml b/php/tasks/php_stretch_sury.yml new file mode 100644 index 00000000..be549804 --- /dev/null +++ b/php/tasks/php_stretch_sury.yml @@ -0,0 +1,23 @@ +--- + +- name: Setup deb.sury.org repository - Add GPG key + get_url: + url: https://packages.sury.org/php/apt.gpg + dest: /etc/apt/trusted.gpg.d/sury.gpg + mode: "0644" + +- name: Setup deb.sury.org repository - Install apt-transport-https + apt: + state: present + name: apt-transport-https + +- name: Setup deb.sury.org repository - Add preferences file + copy: + src: sury.preferences + dest: /etc/apt/preferences.d/z-sury + +- name: Setup deb.sury.org repository - Add source list + apt_repository: + repo: "deb https://packages.sury.org/php/ stretch main" + filename: sury + state: present diff --git a/postfix/README.md b/postfix/README.md index 67f56298..04bf879a 100644 --- a/postfix/README.md +++ b/postfix/README.md @@ -4,9 +4,10 @@ Installation and basic configuration of Postfix. ## Tasks -Minimal configuration is in `tasks/main.yml` and optional customization in : +Minimal configuration is in `tasks/minimal.yml` and optional customization in : * `slow_transport.yml` : slow transport to specific destination. +* `packmail.yml` : config for virtual mail accounts with OpenLDAP ## Available variables @@ -14,5 +15,7 @@ Main variables are : * `postfix_hostname` : hostname for Postfix ; * `postfix_slow_transport` : enable customization for delivrability. +* `postfix_force_main_cf` : force copy of main.cf +* `postfix_packmail` : install an Evolix Packmail instead of lite postfix config The full list of variables (with default values) can be found in `defaults/main.yml`. diff --git a/postfix/defaults/main.yml b/postfix/defaults/main.yml index f0673d65..55ab72cd 100644 --- a/postfix/defaults/main.yml +++ b/postfix/defaults/main.yml @@ -1,3 +1,5 @@ --- postfix_hostname: "{{ ansible_fqdn }}" -postfix_slow_transport_include: False +postfix_force_main_cf: False +postfix_packmail: False +postfix_slow_transport_include: "{{ postfix_packmail }}" diff --git a/postfix/files/cn4evolix.ldif b/postfix/files/cn4evolix.ldif new file mode 100644 index 00000000..a17532ad --- /dev/null +++ b/postfix/files/cn4evolix.ldif @@ -0,0 +1,63 @@ +dn: cn={4}evolix,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: {4}evolix +olcAttributeTypes: {0}( 1.3.6.1.4.1.24331.22.1.1 NAME 'maildrop' DESC 'mail fo + rward' SUP mail ) +olcAttributeTypes: {1}( 1.3.6.1.4.1.24331.22.1.2 NAME 'mailacceptinggeneralid' + DESC 'mail alias' SUP mail ) +olcAttributeTypes: {2}( 1.3.6.1.4.1.24331.22.1.3 NAME 'isActive' DESC 'boolean + to verify an global account is active or not' EQUALITY booleanMatch SYNTAX 1 + .3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {3}( 1.3.6.1.4.1.24331.22.1.4 NAME 'accountActive' DESC 'bo + olean to verify if an mail account is active' EQUALITY booleanMatch SYNTAX 1. + 3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {4}( 1.3.6.1.4.1.24331.22.1.5 NAME 'authsmtpActive' DESC 'b + oolean to verify if SMTP-AUTH is enabled for entry' EQUALITY booleanMatch SYN + TAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {5}( 1.3.6.1.4.1.24331.22.1.6 NAME 'courierActive' DESC 'bo + olean to verify if Courier POP/IMAP is enabled for entry' EQUALITY booleanMat + ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {6}( 1.3.6.1.4.1.24331.22.1.7 NAME 'webmailActive' DESC 'bo + olean to verify if webmail is enabled for entry' EQUALITY booleanMatch SYNTAX + 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {7}( 1.3.6.1.4.1.24331.22.1.8 NAME 'isAdmin' DESC 'boolean + to verify if entry is admin for entry' EQUALITY booleanMatch SYNTAX 1.3.6.1.4 + .1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {8}( 1.3.6.1.4.1.24331.22.1.9 NAME 'postfixTransport' DESC + 'transport for Postfix' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.11 + 5.121.1.26{20} SINGLE-VALUE ) +olcAttributeTypes: {9}( 1.3.6.1.4.1.24331.22.1.10 NAME 'domain' DESC 'Postfix + domain' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTA + X 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +olcAttributeTypes: {10}( 1.3.6.1.4.1.24331.22.1.11 NAME 'quota' DESC 'Courier + maildir quota' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1. + 26 SINGLE-VALUE ) +olcAttributeTypes: {11}( 1.3.6.1.4.1.24331.22.1.16 NAME 'vacationActive' DESC + 'A flag, for marking the user as being away' EQUALITY booleanMatch SYNTAX 1.3 + .6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: {12}( 1.3.6.1.4.1.24331.22.1.17 NAME 'vacationInfo' DESC 'A + bsentee note to leave behind, while on vacation' EQUALITY octetStringMatch SY + NTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) +olcAttributeTypes: {13}( 1.3.6.1.4.1.24331.22.1.18 NAME 'vacationStart' DESC ' + Beginning of vacation' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115. + 121.1.40 SINGLE-VALUE ) +olcAttributeTypes: {14}( 1.3.6.1.4.1.24331.22.1.19 NAME 'vacationEnd' DESC 'En + d of vacation' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 + SINGLE-VALUE ) +olcAttributeTypes: {15}( 1.3.6.1.4.1.24331.22.1.20 NAME 'vacationForward' DESC + 'Where to forward mails to, while on vacation' EQUALITY caseIgnoreIA5Match S + UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} + ) +olcAttributeTypes: {16}( 1.3.6.1.4.1.24331.22.1.21 NAME 'smbActive' DESC 'bool + ean to verify if an Samba account is active' EQUALITY booleanMatch SYNTAX 1.3 + .6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcObjectClasses: {0}( 1.3.6.1.4.1.24331.22.2.1 NAME 'mailAccount' DESC 'LDAP/ + Unix mail account or virtual account' SUP top AUXILIARY MUST ( uid $ mailacce + ptinggeneralid ) MAY ( accountActive $ authsmtpActive $ quota $ isActive $ co + urierActive $ webmailActive $ isAdmin $ vacationActive $ vacationInfo $ vacat + ionStart $ vacationEnd $ vacationForward $ maildrop ) ) +olcObjectClasses: {1}( 1.3.6.1.4.1.24331.22.2.2 NAME 'mailAlias' DESC 'Mail al + iasing/forwarding entry' SUP top STRUCTURAL MUST ( mailacceptinggeneralid $ m + aildrop ) MAY ( cn $ isActive ) ) +olcObjectClasses: {2}( 1.3.6.1.4.1.24331.22.2.4 NAME 'postfixDomain' DESC 'Pos + tfix domain' SUP posixGroup STRUCTURAL MAY ( postfixTransport $ isActive ) ) diff --git a/postfix/files/filter b/postfix/files/filter new file mode 100644 index 00000000..586574a1 --- /dev/null +++ b/postfix/files/filter @@ -0,0 +1 @@ +# Default empty file diff --git a/postfix/files/spam.sh b/postfix/files/spam.sh new file mode 100644 index 00000000..10d5e62a --- /dev/null +++ b/postfix/files/spam.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +#set -x + +umask 022 + +tmp_file=$(mktemp) + +tmp=$(mktemp -d) + +if [ -f $tmp_file ] ; + then rm $tmp_file ; +fi + +sleep $[ $RANDOM / 1024 ] + +# Postfix +cd $tmp + +wget -q -t 3 http://antispam00.evolix.org/spam/client.access -O $tmp_file +cp $tmp_file /etc/postfix/client.access +rm $tmp_file + +wget -q -t 3 http://antispam00.evolix.org/spam/sender.access -O $tmp_file +cp $tmp_file /etc/postfix/sender.access +rm $tmp_file + +wget -q -t 3 http://antispam00.evolix.org/spam/recipient.access -O $tmp_file +cp $tmp_file /etc/postfix/recipient.access +rm $tmp_file + +wget -q -t 3 http://antispam00.evolix.org/spam/header_kill -O $tmp_file +cp $tmp_file /etc/postfix/header_kill +rm $tmp_file + +wget -q -t 3 http://antispam00.evolix.org/spam/sa-blacklist.access -O sa-blacklist.access +wget -q -t 3 http://antispam00.evolix.org/spam/sa-blacklist.access.md5 -O $tmp_file +if md5sum -c $tmp_file > /dev/null && [ -s sa-blacklist.access ] ; then + cp sa-blacklist.access /etc/postfix/sa-blacklist.access +fi +rm sa-blacklist.access +rm $tmp_file + +/usr/sbin/postmap hash:/etc/postfix/client.access +/usr/sbin/postmap hash:/etc/postfix/sender.access +/usr/sbin/postmap hash:/etc/postfix/recipient.access +/usr/sbin/postmap -r hash:/etc/postfix/sa-blacklist.access + +wget -q -t 3 http://antispam00.evolix.org/spam/spamd.cidr -O spamd.cidr +wget -q -t 3 http://antispam00.evolix.org/spam/spamd.cidr.md5 -O $tmp_file +if md5sum -c $tmp_file > /dev/null && [ -s spamd.cidr ] ; then + cp spamd.cidr /etc/postfix/spamd.cidr +fi +rm spamd.cidr +rm $tmp_file + + +# SpamAssassin +cd $tmp +wget -q -t 3 http://antispam00.evolix.org/spam/evolix_rules.cf -O evolix_rules.cf +wget -q -t 3 http://antispam00.evolix.org/spam/evolix_rules.cf.md5 -O $tmp_file +if md5sum -c $tmp_file > /dev/null && [ -s evolix_rules.cf ] ; then + dpkg -l spamassassin 2>&1 | grep -v "no packages found matching" | grep -q ^ii && cp evolix_rules.cf /etc/spamassassin + dpkg -l spamassassin 2>&1 | grep -v "no packages found matching" | grep -q ^ii && /etc/init.d/spamassassin reload > /dev/null + if [ -d /etc/spamassassin/sa-update-hooks.d ]; then + run-parts --lsbsysinit /etc/spamassassin/sa-update-hooks.d + fi +fi + +# ClamAV +cd $tmp +wget -q -t 3 http://antispam00.evolix.org/spam/evolix.ndb -O evolix.ndb +wget -q -t 3 http://antispam00.evolix.org/spam/evolix.ndb.md5 -O $tmp_file +dpkg -l clamav-daemon 2>&1 | grep -v "no packages found matching" | grep -q ^ii && chown clamav: evolix.ndb +if md5sum -c $tmp_file > /dev/null && [ -s evolix.ndb ] ; then + dpkg -l clamav-daemon 2>&1 | grep -v "no packages found matching" | grep -q ^ii && cp -a evolix.ndb /var/lib/clamav/ +fi +wget -q -t 3 http://antispam00.evolix.org/spam/evolix.hsb -O evolix.hsb +wget -q -t 3 http://antispam00.evolix.org/spam/evolix.hsb.md5 -O $tmp_file +dpkg -l clamav-daemon 2>&1 | grep -v "no packages found matching" | grep -q ^ii && chown clamav: evolix.hsb +if md5sum -c $tmp_file > /dev/null && [ -s evolix.hsb ] ; then + dpkg -l clamav-daemon 2>&1 | grep -v "no packages found matching" | grep -q ^ii && cp -a evolix.hsb /var/lib/clamav/ +fi +dpkg -l clamav-daemon 2>&1 | grep -v "no packages found matching" | grep -q ^ii && /etc/init.d/clamav-daemon reload-database > /dev/null +rm $tmp_file + +rm -rf $tmp diff --git a/postfix/meta/main.yml b/postfix/meta/main.yml index a4cc6bd0..3c7b219a 100644 --- a/postfix/meta/main.yml +++ b/postfix/meta/main.yml @@ -13,7 +13,9 @@ galaxy_info: versions: - jessie -dependencies: [] - # List your role dependencies here, one per line. - # Be sure to remove the '[]' above if you add dependencies - # to this list. +dependencies: + - { role: ldap, ldap_schema: 'cn4evolix.ldif', when: postfix_packmail == True } + - { role: spamassasin, when: postfix_packmail == True } + - { role: clamav, when: postfix_packmail == True } + - { role: opendkim, when: postfix_packmail == True } + - { role: dovecot, when: postfix_packmail == True } diff --git a/postfix/tasks/main.yml b/postfix/tasks/main.yml index 49ccb2ac..a1b5a424 100644 --- a/postfix/tasks/main.yml +++ b/postfix/tasks/main.yml @@ -1,30 +1,17 @@ -- name: ensure packages are installed - apt: - name: '{{ item }}' - state: present - with_items: - - postfix - - mailgraph - +--- - name: check if main.cf is default - shell: egrep -v "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | md5sum - + shell: 'grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | md5sum -' changed_when: False check_mode: no register: default_main_cf + tags: + - postfix -- name: create minimal main.cf - template: - src: evolinux_main.cf.j2 - dest: /etc/postfix/main.cf - owner: root - group: root - mode: "0644" - force: yes - when: default_main_cf.stdout == "5450c05d65878e99dad696c7c722e511 -" or - default_main_cf.stdout == "30022953f1f61f002bfb72e163ecb27e -" - notify: restart postfix +- include: minimal.yml + when: postfix_packmail == False -- meta: flush_handlers +- include: packmail.yml + when: postfix_packmail == True - include: slow_transport.yml when: postfix_slow_transport_include diff --git a/postfix/tasks/minimal.yml b/postfix/tasks/minimal.yml new file mode 100644 index 00000000..d1e4b4c5 --- /dev/null +++ b/postfix/tasks/minimal.yml @@ -0,0 +1,24 @@ +--- +- name: ensure packages are installed + apt: + name: '{{ item }}' + state: present + with_items: + - postfix + tags: + - postfix + +- name: create minimal main.cf + template: + src: evolinux_main.cf.j2 + dest: /etc/postfix/main.cf + owner: root + group: root + mode: "0644" + force: yes + notify: restart postfix + when: postfix_force_main_cf == True or + postfix_maincf_md5_jessie in default_main_cf.stdout or + postfix_maincf_md5_stretch in default_main_cf.stdout + tags: + - postfix diff --git a/postfix/tasks/packmail.yml b/postfix/tasks/packmail.yml new file mode 100644 index 00000000..de9ee7ad --- /dev/null +++ b/postfix/tasks/packmail.yml @@ -0,0 +1,117 @@ +--- +- name: ensure packages are installed + apt: + name: '{{ item }}' + state: present + with_items: + - postfix + - postfix-ldap + - postfix-policyd-spf-python + - mailgraph + tags: + - postfix + +- name: create packmail main.cf + template: + src: packmail_main.cf.j2 + dest: /etc/postfix/main.cf + owner: root + group: root + mode: "0644" + force: yes + notify: restart postfix + when: postfix_force_main_cf == True or + postfix_maincf_md5_jessie in default_main_cf.stdout or + postfix_maincf_md5_stretch in default_main_cf.stdout + tags: + - postfix + +- name: deploy packmail master.cf + template: + src: packmail_master.cf.j2 + dest: /etc/postfix/master.cf + mode: "0644" + notify: restart postfix + tags: + - postfix + +- name: copy default filter files + copy: + src: filter + dest: "/etc/postfix/{{ item }}" + force: no + with_items: + - virtual + - client.access + - client.access_local + - header_kill + - header_kill_local + - recipient.access + - recipient.access_local + - sa-blacklist.access + - sender.access + - sender.access_local + - spamd.cidr + register: postfix_copy_filter + tags: + - postfix + +- name: postmap filter files + command: "postmap /etc/postfix/{{ item }}" + with_items: + - virtual + - client.access + - client.access_local + - header_kill + - header_kill_local + - recipient.access + - recipient.access_local + - sa-blacklist.access + - sender.access + - sender.access_local + - spamd.cidr + when: postfix_copy_filter.changed + tags: + - postfix + +- name: deploy ldap postfix config + template: + src: "{{ item }}.j2" + dest: "/etc/postfix/{{ item }}" + mode: "0644" + with_items: + - virtual_aliases.cf + - virtual_domains.cf + - virtual_mailboxes.cf + notify: restart postfix + tags: + - postfix + +- include_role: + name: remount-usr + tags: + - postfix + +- name: copy spam.sh script + copy: + src: spam.sh + dest: /usr/share/scripts/spam.sh + mode: "0700" + tags: + - postfix + +- name: enable spam.sh cron + lineinfile: + dest: /etc/cron.d/spam + line: "42 * * * * /usr/share/scripts/spam.sh" + create: yes + state: present + mode: "0640" + tags: + - postfix + +- name: update antispam list + command: /usr/share/scripts/spam.sh + changed_when: false + tags: + - postfix diff --git a/postfix/tasks/slow_transport.yml b/postfix/tasks/slow_transport.yml index 3bf8ae6d..2f4cab1e 100644 --- a/postfix/tasks/slow_transport.yml +++ b/postfix/tasks/slow_transport.yml @@ -1,10 +1,12 @@ --- - - name: slow transport is defined in master.cf lineinfile: dest: /etc/postfix/master.cf regexp: "^slow " line: "slow unix - - n - - smtp" + notify: restart postfix + tags: + - postfix - name: list of providers for slow transport lineinfile: @@ -21,24 +23,5 @@ - "hotmail.fr slow:" - "hotmail.com slow:" notify: postmap transport - -- name: main.cf is configured for slow transports - blockinfile: - dest: /etc/postfix/main.cf - marker: "# {mark} Slow transports configuration (installed by Ansible)" - block: | - minimal_backoff_time = 2h - maximal_backoff_time = 6h - maximal_queue_lifetime = 4d - queue_run_delay = 100s - bounce_queue_lifetime = 1d - initial_destination_concurrency = 5 - default_destination_concurrency_limit = 20 - slow_destination_rate_delay = 0 - slow_destination_concurrency_limit = 1 - slow_destination_concurrency_failed_cohort_limit = 100 - slow_destination_recipient_limit = 25 - transport_maps = hash:$config_directory/transport - notify: restart postfix - -- meta: flush_handlers + tags: + - postfix diff --git a/postfix/templates/evolinux_main.cf.j2 b/postfix/templates/evolinux_main.cf.j2 index 429e6602..e42a413f 100644 --- a/postfix/templates/evolinux_main.cf.j2 +++ b/postfix/templates/evolinux_main.cf.j2 @@ -13,3 +13,19 @@ recipient_delimiter = + inet_interfaces = all inet_protocols = ipv4 disable_vrfy_command = yes + +{% if postfix_slow_transport_include == True %} +# Slow transports configuration +minimal_backoff_time = 2h +maximal_backoff_time = 6h +maximal_queue_lifetime = 4d +queue_run_delay = 100s +bounce_queue_lifetime = 1d +initial_destination_concurrency = 5 +default_destination_concurrency_limit = 20 +slow_destination_rate_delay = 0 +slow_destination_concurrency_limit = 1 +slow_destination_concurrency_failed_cohort_limit = 100 +slow_destination_recipient_limit = 25 +transport_maps = hash:$config_directory/transport +{% endif %} diff --git a/postfix/templates/packmail_main.cf.j2 b/postfix/templates/packmail_main.cf.j2 new file mode 100644 index 00000000..9f14ec50 --- /dev/null +++ b/postfix/templates/packmail_main.cf.j2 @@ -0,0 +1,423 @@ +## fichier principal de configuration de Postfix +## commentaires de Gregory Colpart reg AT evolix DOT fr +## version 1.0 : 1ere version publique (05.04.2010) + +######################## +# Section : Emplacements +######################## + +# Repertoire ou se trouvent les commandes de postfix [OBLIGATOIRE] +#par defaut, = $program_directory +command_directory = /usr/sbin + +# Repertoire ou se trouvent les demons de postfix [OBLIGATOIRE] +#par defaut, = $program_directory +daemon_directory = /usr/lib/postfix/sbin + +# Variable pour indiquer les emplacements des commandes et demons de postfix +#program_directory = /usr/lib/postfix + +# Repertoire contenant les fichiers de boites aux lettres +#par defaut, = /var/mail +#mail_spool_directory = + +# Repertoire de la file d'attente de postfix +#par defaut, = /var/spool/postfix +#queue_directory = + +# Boites aux lettres +#par defaut, = +home_mailbox = Maildir/ + +# Transmettre les mails a un MDA +#par defaut, = +#mailbox_command = /usr/bin/procmail + +# Separateur entre noms d'utilisateur et extensions d'adresse +# mettre + pour integration avec amavis +#par defaut, = +recipient_delimiter = + + +# Controle si le repertoire existe (souvent pour les systemes de fichiers montes) +#par defaut, = no +#require_home_directory = + +# Commande pour transmettre le courrier a un MDA +#par defaut, = +#mailbox_command = /usr/bin/procmail + +# Banniere SMTP affichee +#par default, = $myhostname ESMTP $mail_name +smtpd_banner = $myhostname ESMTP mail server + +# Groupe des commandes set-gid ayant des acces en ecriture +#par defaut, = postdrop +# setgid_group = postdrop + +# Produire des "biff notifications" aux utilisateurs pour +# prevenir de l'arrivee de nouveaux mails +# par default, = yes +#biff = no + + +#################### +# Section : domaines +#################### + +# Indique le nom d'hote pleinement qualifie ou se trouve postfix [OBLIGATOIRE] +#par defaut, = [retour de la commande Unix hostname] +myhostname = {{ ansible_fqdn }} + +# Variable indiquant le domaine dans lequel se trouve la machine +#par defaut, = [partie domain de la variable $myhostname] +#mydomain = + +# Liste des noms de domaine (ou IP) consideres comme local +#par defaut, = $myhostname, localhost.$mydomain, localhost +mydestination = $myhostname + +# Indique le domaine apparaissant dans le courrier envoye +#par defaut, = $myhostname +myorigin = {{ ansible_fqdn }} + +# Liste de domaine fonctionnant UNIQUEMENT avec des alias virtuels +#par defaut, = $virtual_alias_maps +#virtual_alias_domains = [ domaines avec alias virtuels ] + +# Liste de domaine fonctionnant avec des comptes virtuels +#par defaut, = $virtual_mailbox_maps +virtual_mailbox_domains = ldap:$config_directory/virtual_domains.cf + +# Repertoire de base de l'espace de stockage +#par defaut, = +virtual_mailbox_base = / + +# Ajoute $mydomain aux adresse ne compoirtant que la partie hote sans le domaine +#par defaut, = yes +#append_dot_mydomain = no + +# Ajoute $myorigin aux adresses ne comportant pas de composante de domaine +#par defaut, = yes +#append_at_myorigin = no + +# Liste de domaines cachant des sous-domaines internes +#par defaut, = +#masquerade_domains = + +# A l'exception de certains comptes : +#par defaut, = +#masquerade_exceptions = root, admin + +# Champs d'application de la reecriture des sous-domaines caches +#par defaut, = envelope_sender, header_sender, header_recipient +#masquerade_classes = + +# Sites eligibles pour un vidage rapide (postqueue -s [domain.tld]) +#par defaut, = $relay_domains +#fast_flush_domains = + +# Interfaces sur lesquelles ecoutent postfix +#par defaut, = all +#inet_interfaces = all + +# Adresse IP externe du firewall/proxy si derriere NAT ou proxy +# evite principalement les boucles si MX secondaire et MX primaire indisponible +#par defaut, = +#proxy_interfaces = [adresse IP] + +# Domaines acceptes pour faire relai (MX 2aire) +#relay_domains = [domaine a relayer] + + +########################### +# Section : base de donnees +########################### + +# Liste des bases de donnees utilisees par l'agent de distribution locale +# Pour regenerer une base de donnees : postalias /etc/aliases (par ex) +#par defaut, = hash:/etc/aliases, nis:mail.aliases +alias_maps = hash:/etc/aliases + +# Liste des bases de donnees locales +# Pour regenerer avec newaliases +#par defaut, = hash:/etc/aliases +alias_database = hash:/etc/aliases + +# Chemin vers la commande newaliases +#par defaut, = /usr/bin/newaliases +#newaliases_path = + +# Base de donnes d'alias virtuels +# ne pas oublier : postmap /etc/postfix/virtual +#par defaut, = $virtual_maps +virtual_alias_maps = hash:$config_directory/virtual, ldap:$config_directory/virtual_aliases.cf + +# Base de donners des boites virtuelles +# ne pas oublier : postmap /etc/postfix/vmailbox +#par defaut, = +virtual_mailbox_maps = ldap:$config_directory/virtual_mailboxes.cf + +virtual_uid_maps = static:5000 +virtual_gid_maps = static:5000 +virtual_transport = dovecot +dovecot_destination_recipient_limit = 1 + +# Reecriture des adresses +#par defaut, = +#canonical_maps = hash:/etc/postfix/canonical + +# Reecriture des adresses a l'arrivee (ecrase $canonical_maps) +#par defaut, = +#recipient_canonical_maps = hash:/etc/postfix/canonical + +# Reecriture des adresses au depart +#par defaut, = +#sender_canonical_maps = hash:/etc/postfix/canonical + +# Adresses changees +#relocated_maps = hash:/etc/postfix/relocated + +# Boite pour receptionner tous les utilisateurs inconnus +#luser_relay = spam + +# Liste de base de donnees contenant les adresses locales permettant de rejeter les messages aux utilisateurs inconnus +# (sera nulle pour recuperer les courriels vers les utilisateurs inconnus) +#par defaut, = proxy:unix:passwd.byname $alias_maps +#local_recipient_maps = + +# MAILING-LIST nommee xx +# dans le fichier /etc/aliases : +# xx: user1@domain1 user2@domain2 etc. +# owner-xx: admin@domain +# Utiliser ou non l'alias xx-owner comme adresse d'enveloppe d'expedition +#par defaut, = yes +#owner_request_special = + +# Utiliser l'adresse relle de l'admin au lieu de xx-owner +#par defaut, = no +#expand_owner_alias = + + +########################################### +# Section : parametres de la file d'attente +########################################### + +# Lorsqu'un message n'a pas ete delivre, Postfix adjoint une marque indiquant le moment ou la prochaine tentaive pourra avoir lieu + +# Delai au-dela duquel les messages non delivres seront renvoyes a l'expediteur +#par defaut, = 5d +#maximal_queue_lifetime = + +# Delai au-dela duquel les *bounces* non delivres ne seront plus envoyes +#par defaut, = 5d +bounce_queue_lifetime = 1d + +# Intervalle de temps ou postfix examinera la file +# Il examine notamment la file deferred pour voir si de NOUVEAUX messages sont arrives +# Il faut aussi que la marque indique qu'ils soient prets +#par defaut, = 1000s +#queue_run_delay = + +# A chaque echec, le delai de la prochaine distribution double, avec les restrictions suivantes : +# Delai minimal +#par defaut, = 1000s +#minimal_backoff_time = +# Delai maximal +#par defaut, = 4000s +#maximal_backoff_time = + +# Si maxproc est vide (master.cf), nombre maximal est : +#par defaut, = 100 +#default_process_limit = + +# Nombre maximal de destinataires stockes en memoire par qmgr pour un transport particulier +#par defaut, = 10000 +#default_recipient_limit = + +# Nombre limitant de messages envoyes simultanement INITIALEMENT pour une destination particuliere +# (forcement majoree par maxproc du master.cf ou $default_process_limit) +#par defaut, = 5 +#initial_destination_concurrency = + +# Une fois ces messages distribues, si il reste des messages dans la file d'attente pour cette destination +# particuliere, postfix augmente le nombre de tentative tant qu'il ne detecte pas de probleme avec +# la destination, avec la limite suivante : +#par defaut, = 20 +#default_destination_concurrency_limit = + +# Cette limite peut etre differente selon le type de transport utilise : +#par defaut, = $default_destination_concurrency_limit +#lmtp_destination_concurrency_limit = +#par defaut, = 2 +#local_destination_concurrency_limit = +#par defaut, = $default_destination_concurrency_limit +#relay_destination_concurrency_limit = +#par defaut, = $default_destination_concurrency_limit +#smtp_destination_concurrency_limit = +#par defaut, = $default_destination_concurrency_limit +#virtual_destination_concurrency_limit = + +# On peut aussi limiter le nombre maximum de destinataire pour un meme message +# Si le nombre de destinataire depasse la limite, postfix divise en groupe d'adresses plus petites et envoie des copies distinctes du message +#par defaut, = 10000 +#default_destination_recipient_limit = +#par defaut, = $default_destination_recipient_limit +#lmtp_destination_recipient_limit = +#par defaut, = 1 +#local_destination_recipient_limit = +#par defaut, = 20000 +#qmgr_message_recipient_limit = +#par defaut, = $default_destination_recipient_limit +#relay_destination_recipient_limit = +#par defaut, = $default_destination_recipient_limit +#smtp_destination_recipient_limit = +#par defaut, = 1000 +#smtpd_recipient_limit = +#par defaut, = $default_destination_recipient_limit +#virtual_destination_recipient_limit = + +# Nombre maximum de destinataires pour un transport lorsque priorite superieure de transport +#par defaut, = 1000 +#default_extra_recipient_limit = + +slow_destination_rate_delay = 0 +slow_destination_concurrency_limit = 1 +slow_destination_recipient_limit = 25 +slow_destination_concurrency_failed_cohort_limit = 100 + +# Types d'incidents a rapporter +# resource : message non delivre pour probleme de ressource +# software : message non delivre pour probleme de logiciels +# policy : envoie le transcription smtp d'un message rejete par restrictions +# protocol : envoie toute transcription smtp erronee +# delay : envoie les entetes de messages differes +# bounce : envoie les entetes de tous les message renvoyes +# 2bounce : envoie les entetes de tous les messages renvoyes non delivres +#par defaut, = resource, software +notify_classes = resource, software, bounce, 2bounce, delay, policy, protocol + +# A qui les reporter ? +#Pour delay +#par defaut, = postmaster +delay_notice_recipient = delay +#Pour policy, protocol, resource, software +#par defaut, = postmaster +error_notice_recipient = error +#Pour bounce +#par defaut, = postmaster +bounce_notice_recipient = bounce +#Pour 2bounce +#par defaut, = postmaster +2bounce_notice_recipient = bounce + + +######################## +# Section : restrictions +######################## + +# Restrictions au depart de la conversation +#par defaut, = +smtpd_client_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + cidr:$config_directory/spamd.cidr, + +# Restrictions au niveau de la commande HELO/EHLO +#par defaut, = +smtpd_helo_restrictions = + reject_invalid_hostname + +# Restrictions au niveau de la commande MAIL FROM +#par defaut, = +smtpd_sender_restrictions = + permit_mynetworks, + check_sender_access hash:$config_directory/sa-blacklist.access + +# Restrictions au niveau de la commande MAIL FROM +#par defaut, = permit_mynetworks, reject_unauth_destination +smtpd_recipient_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + reject_unauth_destination, + check_policy_service unix:private/policyd-spf, + check_client_access hash:$config_directory/client.access_local, + check_client_access hash:$config_directory/client.access, + check_sender_access hash:$config_directory/sender.access_local, + check_sender_access hash:$config_directory/sender.access, + check_recipient_access hash:$config_directory/recipient.access_local, + check_recipient_access hash:$config_directory/recipient.access, + reject_unlisted_recipient, + reject_unknown_sender_domain, + reject_non_fqdn_sender, + reject_unauth_pipelining, + +policyd-spf_time_limit = 3600 + +header_checks = + regexp:$config_directory/header_kill_local, + regexp:$config_directory/header_kill + +transport_maps = hash:$config_directory/transport + +# Attendre la commande 'RCPT TO' avant d'evaluer les restrictions ? +# (peut poser pb avec certains clients et permet d'avoir renseignements suppl) +#par defaut, = yes +#smtpd_delay_reject = + +# Definition des plages IP appartenant a mynetworks +#par defaut, toutes les plages d'adresses IPv4 (et IPv6) des interfaces +mynetworks = 127.0.0.0/8,[::1]/128,10.0.0.0/16 + +# Exiger la commande HELO/EHLO +#par defaut, = no +smtpd_helo_required = yes + +# Exiger syntaxe conforme dans les commandes MAIL FROM ou RCPT TO +#par defaut, = no +strict_rfc821_envelopes = yes + +# Rejeter le courrier provenant d'une adresse inexistante ? +#par defaut, = no +#smtpd_reject_unlisted_sender = + +# Rejeter le courrier a destination d'une adresse inexistante ? +#par defaut, = yes +#smtpd_reject_unlisted_recipient = + + +####################### +# Section : Chiffrement +####################### + +smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem +smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# SASL +smtpd_sasl_auth_enable = yes +broken_sasl_auth_clients = yes +smtpd_sasl_type = dovecot +smtpd_sasl_path = private/auth-client + +# Amavis and OpenDKIM +content_filter = smtp-amavis:[127.0.0.1]:10024 +smtpd_milters = inet:[127.0.0.1]:54321 +non_smtpd_milters = inet:[127.0.0.1]:54321 + +{% if postfix_slow_transport_include == True %} +# Slow transports configuration +minimal_backoff_time = 2h +maximal_backoff_time = 6h +maximal_queue_lifetime = 4d +queue_run_delay = 100s +bounce_queue_lifetime = 1d +initial_destination_concurrency = 5 +default_destination_concurrency_limit = 20 +slow_destination_rate_delay = 0 +slow_destination_concurrency_limit = 1 +slow_destination_concurrency_failed_cohort_limit = 100 +slow_destination_recipient_limit = 25 +transport_maps = hash:$config_directory/transport +{% endif %} diff --git a/postfix/templates/packmail_master.cf.j2 b/postfix/templates/packmail_master.cf.j2 new file mode 100644 index 00000000..7326cb35 --- /dev/null +++ b/postfix/templates/packmail_master.cf.j2 @@ -0,0 +1,171 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master" or +# on-line: http://www.postfix.org/master.5.html). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (no) (never) (100) +# ========================================================================== +smtp inet n - y - - smtpd +#smtp inet n - y - 1 postscreen +#smtpd pass - - y - - smtpd +#dnsblog unix - - y - 0 dnsblog +#tlsproxy unix - - y - 0 tlsproxy +submission inet n - y - - smtpd + -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o smtpd_sasl_auth_enable=yes + -o smtpd_client_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING +smtps inet n - y - - smtpd + -o syslog_name=postfix/smtps + -o smtpd_tls_wrappermode=yes + -o smtpd_sasl_auth_enable=yes + -o smtpd_client_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING +#628 inet n - y - - qmqpd +pickup unix n - y 60 1 pickup +cleanup unix n - y - 0 cleanup +qmgr unix n - n 300 1 qmgr +#qmgr unix n - n 300 1 oqmgr +tlsmgr unix - - y 1000? 1 tlsmgr +rewrite unix - - y - - trivial-rewrite +bounce unix - - y - 0 bounce +defer unix - - y - 0 bounce +trace unix - - y - 0 bounce +verify unix - - y - 1 verify +flush unix n - y 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - y - - smtp +# When relaying mail as backup MX, disable fallback_relay to avoid MX loops +relay unix - - y - - smtp + -o smtp_fallback_relay= +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 +showq unix n - y - - showq +error unix - - y - - error +retry unix - - y - - error +discard unix - - y - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - y - - lmtp +anvil unix - - y - 1 anvil +scache unix - - y - 1 scache +# +# ==================================================================== +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# +# Many of the following services use the Postfix pipe(8) delivery +# agent. See the pipe(8) man page for information about ${recipient} +# and other message envelope options. +# ==================================================================== +# +# maildrop. See the Postfix MAILDROP_README file for details. +# Also specify in main.cf: maildrop_destination_recipient_limit=1 +# +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +# +# ==================================================================== +# +# Recent Cyrus versions can use the existing "lmtp" master.cf entry. +# +# Specify in cyrus.conf: +# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 +# +# Specify in main.cf one or more of the following: +# mailbox_transport = lmtp:inet:localhost +# virtual_transport = lmtp:inet:localhost +# +# ==================================================================== +# +# Cyrus 2.1.5 (Amos Gouaux) +# Also specify in main.cf: cyrus_destination_recipient_limit=1 +# +#cyrus unix - n n - - pipe +# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} +# +# ==================================================================== +# Old example of delivery via Cyrus. +# +#old-cyrus unix - n n - - pipe +# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} +# +# ==================================================================== +# +# See the Postfix UUCP_README file for configuration details. +# +uucp unix - n n - - pipe + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +# +# Other external delivery methods. +# +ifmail unix - n n - - pipe + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe + flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient +scalemail-backend unix - n n - 2 pipe + flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} +mailman unix - n n - - pipe + flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py + ${nexthop} ${user} + +slow unix - - n - - smtp + +policyd-spf unix - n n - 0 spawn + user=policyd-spf argv=/usr/bin/policyd-spf + +dovecot unix - n n - - pipe + flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient} + +scan unix - - y - 10 smtp +localhost:10026 inet n - y - 10 smtpd + -o content_filter= + -o local_recipient_maps= + -o relay_recipient_maps= + -o myhostname=filter.mynetwork.local + -o smtpd_helo_restrictions= + -o smtpd_client_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o mynetworks=127.0.0.0/8 + +smtp-amavis unix - - y - 2 lmtp + -o lmtp_data_done_timeout=1200 + -o lmtp_send_xforward_command=yes + +127.0.0.1:10025 inet n - y - - smtpd + -o content_filter= + -o smtpd_milters= + -o local_recipient_maps= + -o relay_recipient_maps= + -o smtpd_restriction_classes= + -o smtpd_delay_reject=no + -o smtpd_client_restrictions=permit_mynetworks,reject + -o smtpd_helo_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o smtpd_data_restrictions=reject_unauth_pipelining + -o smtpd_end_of_data_restrictions= + -o mynetworks=127.0.0.0/8 + -o strict_rfc821_envelopes=yes + -o smtpd_error_sleep_time=0 + -o smtpd_soft_error_limit=1001 + -o smtpd_hard_error_limit=1000 + -o smtpd_client_connection_count_limit=0 + -o smtpd_client_connection_rate_limit=0 + -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks + +pre-cleanup unix n - n - 0 cleanup + -o virtual_alias_maps= + -o canonical_maps= + -o sender_canonical_maps= + -o recipient_canonical_maps= + -o masquerade_domains= + -o always_bcc= + -o sender_bcc_maps= + -o recipient_bcc_maps= diff --git a/postfix/templates/virtual_aliases.cf.j2 b/postfix/templates/virtual_aliases.cf.j2 new file mode 100644 index 00000000..1a6e5f9c --- /dev/null +++ b/postfix/templates/virtual_aliases.cf.j2 @@ -0,0 +1,5 @@ +search_base = {{ ldap_suffix }} +query_filter = (&(mailacceptinggeneralid=%u@%d)(isActive=TRUE)) +result_attribute = maildrop +version = 3 +aliases_scope = sub diff --git a/postfix/templates/virtual_domains.cf.j2 b/postfix/templates/virtual_domains.cf.j2 new file mode 100644 index 00000000..97e9ebb3 --- /dev/null +++ b/postfix/templates/virtual_domains.cf.j2 @@ -0,0 +1,5 @@ +search_base = {{ ldap_suffix }} +query_filter = (&(cn=%s)(objectClass=postfixDomain)(isActive=TRUE)) +result_attribute = cn +scope = sub +version = 3 diff --git a/postfix/templates/virtual_mailboxes.cf.j2 b/postfix/templates/virtual_mailboxes.cf.j2 new file mode 100644 index 00000000..0796bdf6 --- /dev/null +++ b/postfix/templates/virtual_mailboxes.cf.j2 @@ -0,0 +1,5 @@ +search_base = {{ ldap_suffix }} +query_filter = (&(mailacceptinggeneralid=%s)(objectClass=mailAccount)(isActive=TRUE)(accountActive=TRUE)) +result_attribute = homeDirectory +scope = sub +version = 3 diff --git a/postfix/vars/main.yml b/postfix/vars/main.yml new file mode 100644 index 00000000..e8a773c9 --- /dev/null +++ b/postfix/vars/main.yml @@ -0,0 +1,5 @@ +--- +## MD5 hash of default main.cf filter, obtained with this command : +# grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | md5sum - +postfix_maincf_md5_jessie: "5450c05d65878e99dad696c7c722e511" +postfix_maincf_md5_stretch: "30022953f1f61f002bfb72e163ecb27e" diff --git a/postgresql/defaults/main.yml b/postgresql/defaults/main.yml index 543f1707..6ee57747 100644 --- a/postgresql/defaults/main.yml +++ b/postgresql/defaults/main.yml @@ -9,4 +9,4 @@ postgresql_random_page_cost: 1.5 postgresql_effective_cache_size: "{{ (ansible_memtotal_mb * 0.5) | int }}MB" # PostgreSQL version -postgresql_version: '9.4' +postgresql_version: '9.6' diff --git a/postgresql/tasks/main.yml b/postgresql/tasks/main.yml index b090b09d..3bc1f904 100644 --- a/postgresql/tasks/main.yml +++ b/postgresql/tasks/main.yml @@ -1,9 +1,10 @@ --- -- include: pgdg-repo.yml - when: postgresql_version != '9.4' +- include: packages_jessie.yml + when: ansible_distribution_release == "jessie" -- include: packages.yml +- include: packages_stretch.yml + when: ansible_distribution_major_version | version_compare('9', '>=') - include: config.yml diff --git a/postgresql/tasks/packages_jessie.yml b/postgresql/tasks/packages_jessie.yml new file mode 100644 index 00000000..abf0ad08 --- /dev/null +++ b/postgresql/tasks/packages_jessie.yml @@ -0,0 +1,12 @@ +--- + +- include: pgdg-repo.yml + when: postgresql_version != '9.4' + +- name: Install postgresql package + apt: + name: '{{item}}' + with_items: + - "postgresql-{{postgresql_version}}" + - ptop + - libdbd-pg-perl diff --git a/postgresql/tasks/packages.yml b/postgresql/tasks/packages_stretch.yml similarity index 69% rename from postgresql/tasks/packages.yml rename to postgresql/tasks/packages_stretch.yml index cd4f3efa..334a1dff 100644 --- a/postgresql/tasks/packages.yml +++ b/postgresql/tasks/packages_stretch.yml @@ -4,5 +4,6 @@ apt: name: '{{item}}' with_items: - - "postgresql-{{postgresql_version}}" + - postgresql - ptop + - libdbd-pg-perl diff --git a/postgresql/templates/postgresql.conf b/postgresql/templates/postgresql.conf index eafadeb9..ebb6dde2 100644 --- a/postgresql/templates/postgresql.conf +++ b/postgresql/templates/postgresql.conf @@ -3,7 +3,7 @@ shared_buffers = {{ postgresql_shared_buffers }} work_mem = {{ postgresql_work_mem }} #shared_preload_libraries = 'pg_stat_statements' #synchronous_commit = off -{% if postgresql_version |version_compare('9.5', '<') %} +{% if postgresql_version | version_compare('9.5', '<') %} checkpoint_segments = 30 {% else %} max_wal_size = 15GB diff --git a/proftpd/README.md b/proftpd/README.md index 4b2faa95..1fcb4910 100644 --- a/proftpd/README.md +++ b/proftpd/README.md @@ -12,5 +12,7 @@ Main variables are : * `proftpd_hostname`: hostname (default: `ansible_hostname`) * `proftpd_fqdn`: fully qualified domain name (default: `ansible_fqdn`) +* `proftpd_default_address` : address for the server to listen on (default: `[]`) +* `proftpd_port` : port for the control socket (default: `21`) The full list of variables (with default values) can be found in `defaults/main.yml`. diff --git a/proftpd/defaults/main.yml b/proftpd/defaults/main.yml index 5355ea43..3dc9511c 100644 --- a/proftpd/defaults/main.yml +++ b/proftpd/defaults/main.yml @@ -1,3 +1,5 @@ --- proftpd_hostname: "{{ ansible_hostname }}" proftpd_fqdn: "{{ ansible_fqdn }}" +proftpd_default_address: [] +proftpd_port: "21" diff --git a/proftpd/files/vpasswd b/proftpd/files/vpasswd new file mode 100644 index 00000000..c7f074ae --- /dev/null +++ b/proftpd/files/vpasswd @@ -0,0 +1 @@ +# username:password:uid:gid:gecos:homedir:shell diff --git a/proftpd/meta/main.yml b/proftpd/meta/main.yml index 7b590850..d08211b1 100644 --- a/proftpd/meta/main.yml +++ b/proftpd/meta/main.yml @@ -12,6 +12,7 @@ galaxy_info: - name: Debian versions: - jessie + - stretch dependencies: [] # List your role dependencies here, one per line. diff --git a/proftpd/tasks/main.yml b/proftpd/tasks/main.yml index 3f6b3abe..a0c5fbb2 100644 --- a/proftpd/tasks/main.yml +++ b/proftpd/tasks/main.yml @@ -20,6 +20,7 @@ src: evolinux.conf.j2 dest: /etc/proftpd/conf.d/z-evolinux.conf mode: "0644" + force: no notify: restart proftpd tags: - proftpd @@ -32,3 +33,25 @@ notify: restart proftpd tags: - proftpd + +- name: Put empty vpasswd file if missing + copy: + src: vpasswd + dest: /etc/proftpd/vpasswd + force: no + notify: restart proftpd + tags: + - proftpd + +# Why 440? Because should be edited with ftpasswd. +# So, readonly when opened with vim. +# Then readable by group. +- name: Enforce permissions on password file + file: + path: /etc/proftpd/vpasswd + mode: "0440" + owner: root + group: root + notify: restart proftpd + tags: + - proftpd diff --git a/proftpd/templates/evolinux.conf.j2 b/proftpd/templates/evolinux.conf.j2 index d6e8b565..8a810a99 100644 --- a/proftpd/templates/evolinux.conf.j2 +++ b/proftpd/templates/evolinux.conf.j2 @@ -15,6 +15,10 @@ PassivePorts 60000 61000 UseReverseDNS off IdentLookups off TimesGMT off +Port {{ proftpd_port }} +{% if proftpd_default_address != [] %} +DefaultAddress {{ proftpd_default_address | join(' ') }} +{% endif %} # Local permissions DefaultRoot ~ diff --git a/redis/README.md b/redis/README.md index 29ff132f..5a7168b7 100644 --- a/redis/README.md +++ b/redis/README.md @@ -16,6 +16,7 @@ Main variables are : * `redis_conf_path`: config file location ; * `redis_port`: listening TCP port ; * `redis_bind_interface`: listening IP address ; +* `redis_password`: password for redis. Empty means no password ; * `redis_unixsocket`: Unix socket ; * `redis_loglevel`: log verbosity ; * `redis_logfile`: log file location. diff --git a/redis/defaults/main.yml b/redis/defaults/main.yml index cf4e5fef..6526c887 100644 --- a/redis/defaults/main.yml +++ b/redis/defaults/main.yml @@ -7,6 +7,8 @@ redis_bind_interface: 127.0.0.1 redis_unixsocket: '/var/run/redis/redis.sock' redis_timeout: 300 +redis_password: NULL + redis_loglevel: "notice" redis_logfile: /var/log/redis/redis-server.log diff --git a/redis/handlers/main.yml b/redis/handlers/main.yml index 8a416b0e..49b906a1 100644 --- a/redis/handlers/main.yml +++ b/redis/handlers/main.yml @@ -8,3 +8,8 @@ service: name: munin-node state: restarted + +- name: restart nagios-nrpe-server + service: + name: nagios-nrpe-server + state: restarted diff --git a/redis/tasks/main.yml b/redis/tasks/main.yml index 1b0545fa..33a70797 100644 --- a/redis/tasks/main.yml +++ b/redis/tasks/main.yml @@ -1,8 +1,11 @@ --- - name: Redis is installed. apt: - name: redis-server + name: "{{ item }}" state: present + with_items: + - redis-server + - redis-tools tags: - redis - packages @@ -31,3 +34,12 @@ - include: munin.yml when: _munin_installed.stat.exists and _munin_installed.stat.isdir + +- name: is NRPE present ? + stat: + path: /etc/nagios/nrpe.d/evolix.cfg + check_mode: no + register: nrpe_evolix_config + +- include: nrpe_stretch.yml + when: ansible_distribution_release == "stretch" and nrpe_evolix_config.stat.exists == true diff --git a/redis/tasks/munin.yml b/redis/tasks/munin.yml index 07473e2f..0d8a27f6 100644 --- a/redis/tasks/munin.yml +++ b/redis/tasks/munin.yml @@ -6,23 +6,10 @@ tags: - redis -- name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - check_mode: no - register: usr_partition - tags: redis - -- name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 - tags: redis +- include_role: + name: remount-usr + tags: + - redis - name: Create plugin directory file: @@ -60,3 +47,26 @@ - used_memory notify: restart munin-node tags: redis + +- name: Count redis condif blocks in munin-node configuration + command: grep -c "\[redis_" /etc/munin/plugin-conf.d/munin-node + register: munin_redis_blocs_in_config + failed_when: False + changed_when: False + check_mode: no + +- name: Add redis password for munin (if no more than 1 config block) + ini_file: + dest: /etc/munin/plugin-conf.d/munin-node + section: 'redis_*' + option: env.password + value: '{{ redis_password }}' + notify: restart munin-node + when: "redis_password != '' and redis_password != None and {{munin_redis_blocs_in_config.stdout | int}} <= 1" + tags: redis + + +- name: Warn if multiple instance in munin-plugins configuration + debug: + msg: "WARNING - It seems you have multiple redis sections in your munin-node configuration - Munin config NOT changed" + when: "redis_password != '' and redis_password != None and {{munin_redis_blocs_in_config.stdout | int}} > 1 " diff --git a/redis/tasks/nrpe_stretch.yml b/redis/tasks/nrpe_stretch.yml new file mode 100644 index 00000000..c78e5a28 --- /dev/null +++ b/redis/tasks/nrpe_stretch.yml @@ -0,0 +1,18 @@ +--- +- name: Install perl lib-redis (needed by check_redis) + apt: + name: libredis-perl + state: present + tags: + - redis + - nrpe + +- name: Replace check_tcp by check_redis for NRPE + replace: + dest: /etc/nagios/nrpe.d/evolix.cfg + regexp: '^command\[check_redis\]=.+' + replace: 'command[check_redis]=/usr/lib/nagios/plugins/check_redis -H 127.0.0.1' + notify: restart nagios-nrpe-server + tags: + - redis + - nrpe diff --git a/redis/templates/redis.conf.j2 b/redis/templates/redis.conf.j2 index f7a7c5f0..78dd0c8c 100644 --- a/redis/templates/redis.conf.j2 +++ b/redis/templates/redis.conf.j2 @@ -7,6 +7,10 @@ bind {{ redis_bind_interface }} unixsocket {{ redis_unixsocket }} {% endif %} +{% if redis_password %} +requirepass {{ redis_password }} +{% endif %} + timeout {{ redis_timeout }} loglevel {{ redis_loglevel }} diff --git a/redmine/files/puma.service b/redmine/files/puma.service index 65aab8fb..6e993607 100644 --- a/redmine/files/puma.service +++ b/redmine/files/puma.service @@ -13,5 +13,5 @@ KillMode=process #Restart=on-failure [Install] -WantedBy=multi-user.target +WantedBy=default.target Alias=puma.service diff --git a/redmine/templates/additional_environment.rb.j2 b/redmine/templates/additional_environment.rb.j2 index b1211a2e..b6065a57 100644 --- a/redmine/templates/additional_environment.rb.j2 +++ b/redmine/templates/additional_environment.rb.j2 @@ -1 +1,2 @@ config.paths['log'] = "/home/{{ redmine_user }}/log/redmine.log" +config.log_level = :warn diff --git a/remount-usr/handlers/main.yml b/remount-usr/handlers/main.yml new file mode 100644 index 00000000..5f197e78 --- /dev/null +++ b/remount-usr/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: remount usr + command: "mount -o remount /usr" + failed_when: false + args: + warn: no diff --git a/remount-usr/tasks/main.yml b/remount-usr/tasks/main.yml new file mode 100644 index 00000000..cdc7e10e --- /dev/null +++ b/remount-usr/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: "check if /usr is a read-only partition" + command: 'grep -E " /usr.*ro" /proc/mounts' + args: + warn: no + changed_when: False + failed_when: False + check_mode: no + register: usr_partition + +- name: "mount /usr in rw" + command: 'mount -o remount,rw /usr' + args: + warn: no + when: usr_partition.rc == 0 + notify: remount usr diff --git a/spamassasin/files/sa-update.sh b/spamassasin/files/sa-update.sh new file mode 100644 index 00000000..b138c285 --- /dev/null +++ b/spamassasin/files/sa-update.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +# Evolix sa-update, based on: +# Duncan Findlay +# duncf@debian.org + +mail=$(grep EVOMAINTMAIL /etc/evomaintenance.cf | cut -d'=' -f2) +test -x /usr/bin/sa-update || exit 0 +test -x /etc/init.d/spamassassin || exit 0 + +# If there's a problem with the ruleset or configs, print the output +# of spamassassin --lint (which will typically get emailed to root) +# and abort. +die_with_lint() { + su debian-spamd -c "spamassassin --lint -D 2>&1" + exit 1 +} + +do_compile() { +# Compile, if rules have previously been compiled, and it's possible + if [ -x /usr/bin/re2c -a -x /usr/bin/sa-compile \ + -a -d /var/lib/spamassassin/compiled ]; then + su debian-spamd -c "sa-compile --quiet" + # Fixup perms -- group and other should be able to + # read and execute, but never write. Works around + # sa-compile's failure to obey umask. + chmod -R go-w,go+rX /var/lib/spamassassin/compiled + fi +} + +# Tell a running spamd to reload its configs and rules. +reload() { + # Reload + if which invoke-rc.d >/dev/null 2>&1; then + invoke-rc.d spamassassin reload > /dev/null + else + /etc/init.d/spamassassin reload > /dev/null + fi + if [ -d /etc/spamassassin/sa-update-hooks.d ]; then + run-parts --lsbsysinit /etc/spamassassin/sa-update-hooks.d + fi +} + +# Update +umask 022 +su debian-spamd -c "sa-update --gpghomedir /var/lib/spamassassin/sa-update-keys" + +case $? in + 0) + # got updates! + su debian-spamd -c "spamassassin --lint" || die_with_lint + do_compile + reload + echo -e "Les règles SpamAsassin ont été mises à jour. Merci de reporter toute anomalie." | \ + mail -s "SpamAsassin's rules updated." $mail + ;; + 1) + # no updates + exit 0 + ;; + 2) + # lint failed! + die_with_lint + ;; + *) + echo "sa-update failed for unknown reasons" 1>&2 + ;; +esac diff --git a/spamassasin/files/spamassassin.cf b/spamassasin/files/spamassassin.cf new file mode 100644 index 00000000..821f51d4 --- /dev/null +++ b/spamassasin/files/spamassassin.cf @@ -0,0 +1,117 @@ +#required_score 5 -> assure par Amavis +report_safe 0 +#rewrite_header Subject [SPAM] -> assure par Amavis +add_header all Report _REPORT_ + +# filtre bayesien +# mkdir -p /var/spool/spam/ && chown amavis /var/spool/spam/ +use_bayes 1 +bayes_auto_learn 1 +bayes_path /var/spool/spam/bayes +bayes_file_mode 0777 + +# AWL : AutoWhitelist +# mkdir -p /var/spool/spam/ && chown amavis /var/spool/spam/ +loadplugin Mail::SpamAssassin::Plugin::AWL +use_auto_whitelist 1 +auto_whitelist_path /var/spool/spam/auto_whitelist +auto_whitelist_file_mode 0666 + +# LANG TESTS +loadplugin Mail::SpamAssassin::Plugin::TextCat +ok_languages en fr es it +ok_locales en fr es it + +score BODY_8BITS 1.500 +score CHARSET_FARAWAY 3.200 +score CHARSET_FARAWAY_HEADER 3.200 +score HTML_CHARSET_FARAWAY 0.500 +score MIME_CHARSET_FARAWAY 2.450 +score UNWANTED_LANGUAGE_BODY 2.800 + +# DCC +# use_dcc 1 => un plugin maintenant... +score DCC_CHECK 2.9 + +# RAZOR : http://razor.sourceforge.net +use_razor2 1 +score RAZOR2_CHECK 2.9 +score RAZOR2_CF_RANGE_51_100 1.3 + +# pyzor : http://pyzor.sourceforge.net/ +use_pyzor 0 + +# RBL (Realtime Blackhole List) +skip_rbl_checks 0 +score RCVD_IN_BL_SPAMCOP_NET 3 + +# misc +score HELO_DYNAMIC_IPADDR 0.3 +score BIZ_TLD 0.1 +score PRIORITY_NO_NAME 0.2 + +# disable HTML tests + +score HTML_MESSAGE 0 +score HTML_00_10 0 +score HTML_10_20 0 +score HTML_20_30 0 +score HTML_30_40 0 +score HTML_40_50 0 +score HTML_50_60 0 +score HTML_60_70 0 +score HTML_70_80 0 +score HTML_80_90 0 +score HTML_90_100 0 +#score HTML_COMMENT_8BITS 0 +score UPPERCASE_25_50 0 +score UPPERCASE_50_75 0 +score UPPERCASE_75_100 0 +score MIME_HTML_ONLY 0.1 +# From http://maxime.ritter.eu.org/Spam/user_prefs +# Trop de faux negatifs avec BAYES_(0|1|2|3|4)* +score BAYES_00 0 0 -0.01 -0.01 +score BAYES_01 0 0 -0.01 -0.01 +score BAYES_10 0 0 -0.01 -0.01 +score BAYES_20 0 0 -0.01 -0.01 +score BAYES_30 0 0 -0.01 -0.01 +score BAYES_40 0 0 -0.01 -0.01 +score BAYES_44 0 0 -0.01 -0.01 +score BAYES_50 0 0 0.1 0.1 +score BAYES_56 0 0 0.5 0.5 +score BAYES_60 0 0 1.0 1.0 +score BAYES_70 0 0 2.5 2.5 +score BAYES_80 0 0 3.5 3.5 +score BAYES_90 0 0 4.5 4.5 +score BAYES_99 0 0 8.0 8.0 + +score RCVD_IN_SORBS_DUL 0.3 +score SUBJ_ILLEGAL_CHARS 0 +score RCVD_IN_NJABL_DUL 0.3 + +score ADDRESS_IN_SUBJECT 0.1 + +score HELO_LH_HOME 1.0 + +#internal_networks 192.168.XXX/24 +trusted_networks 62.212.111.216 88.179.18.233 85.118.59.50 31.170.8.0/21 +#score ALL_TRUSTED 0.3 +score HELO_DYNAMIC_IPADDR 0.3 + +score FORGED_MUA_OUTLOOK 0.5 + +# Eudora sucks +score EXTRA_MPART_TYPE 0.1 +score MIME_BOUND_EQ_REL 0.1 +score MIME_QP_LONG_LINE 0.1 + +# SMTP senders *have* dynamic IP addresses +# A.B.C.D.dnsbl.sorbs.net -> 127.0.0.10 +score RCVD_IN_DYNABLOCK 0 +score HELO_DYNAMIC_IPADDR 0.3 +score RCVD_IN_SORBS 0.1 +score RCVD_IN_PBL 0.1 +score RCVD_IN_SORBS_DUL 0 + +# old bug... +score FH_DATE_PAST_20XX 0.0 diff --git a/spamassasin/handlers/main.yml b/spamassasin/handlers/main.yml new file mode 100644 index 00000000..7479d736 --- /dev/null +++ b/spamassasin/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart spamassassin + service: + name: spamassassin + state: restarted diff --git a/spamassasin/meta/main.yml b/spamassasin/meta/main.yml new file mode 100644 index 00000000..510b6855 --- /dev/null +++ b/spamassasin/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: amavis } diff --git a/spamassasin/tasks/main.yml b/spamassasin/tasks/main.yml new file mode 100644 index 00000000..cfcfa09b --- /dev/null +++ b/spamassasin/tasks/main.yml @@ -0,0 +1,57 @@ +--- +- name: install SpamAssasin + apt: + name: "{{ item }}" + state: present + with_items: + - spamassassin + - evomaintenance + tags: + - spamassassin + +- name: configure SpamAssasin + copy: + src: spamassassin.cf + dest: /etc/spamassassin/local_evolix.cf + mode: "0644" + notify: restart spamassassin + tags: + - spamassassin + +- name: enable SpamAssasin + replace: + dest: /etc/default/spamassassin + regexp: 'ENABLED=0' + replace: 'ENABLED=1' + notify: restart spamassassin + tags: + - spamassassin + +- include_role: + name: remount-usr + tags: + - spamassassin + +- name: copy sa-update.sh script + copy: + src: sa-update.sh + dest: /usr/share/scripts/sa-update.sh + mode: "0750" + tags: + - spamassassin + +- name: enable sa-update.sh cron + lineinfile: + dest: /etc/cron.d/sa-update + line: "42 6 5 1,4,7,10 * /usr/share/scripts/sa-update.sh" + create: yes + state: present + mode: "0640" + tags: + - spamassassin + +- name: update SpamAssasin's rules + command: "/usr/share/scripts/sa-update.sh" + changed_when: false + tags: + - spamassassin diff --git a/supervisord/handlers/main.yml b/supervisord/handlers/main.yml index 3bf89428..be10ba0a 100644 --- a/supervisord/handlers/main.yml +++ b/supervisord/handlers/main.yml @@ -1,5 +1,5 @@ --- -- name: Restart supervisord +- name: restart supervisor service: name: supervisor state: restarted diff --git a/supervisord/tasks/main.yml b/supervisord/tasks/main.yml index 500c5d68..17d7737a 100644 --- a/supervisord/tasks/main.yml +++ b/supervisord/tasks/main.yml @@ -1,13 +1,17 @@ --- -- name: Install supervisord +- name: Install Supervisor apt: name: supervisor + tags: + - supervisord -- name: Add http configuration for supvervisord +- name: Add http configuration for Supervisor copy: src: http.conf dest: /etc/supervisor/conf.d/ mode: "0644" force: no - notify: Restart supervisord + notify: restart supervisor when: supervisord_enable_http + tags: + - supervisord diff --git a/tomcat/tasks/nagios.yml b/tomcat/tasks/nagios.yml index 01de5348..69c99810 100644 --- a/tomcat/tasks/nagios.yml +++ b/tomcat/tasks/nagios.yml @@ -4,21 +4,8 @@ name: monitoring-plugins state: present -- name: Check if /usr is a partition - shell: "mount | grep 'on /usr type'" - args: - warn: no - changed_when: False - failed_when: False - check_mode: no - register: usr_partition - -- name: Mount /usr in rw - command: mount -o remount,rw /usr - args: - warn: no - changed_when: False - when: usr_partition.rc == 0 +- include_role: + name: remount-usr - name: Create Nagios plugins dir file: diff --git a/varnish/tasks/munin.yml b/varnish/tasks/munin.yml index 1c2ad790..552c8a34 100644 --- a/varnish/tasks/munin.yml +++ b/varnish/tasks/munin.yml @@ -4,7 +4,9 @@ name: libxml-parser-perl tags: varnish -- include: remount_usr_rw.yml +- include_role: + name: remount-usr + tags: varnish - name: Create plugin directory file: diff --git a/varnish/tasks/remount_usr_rw.yml b/varnish/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/varnish/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/webapps/README.md b/webapps/README.md deleted file mode 100644 index 2c74fa01..00000000 --- a/webapps/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# webapps - -Install popular webapps - -## Tasks - -Tasks are extracted in several files, included in `tasks/main.yml` : - -* `wordpress.yml` : wordpress installation - -## Available variables - -* `webapp_wordpress_install` : enable wordpress installation diff --git a/webapps/defaults/main.yml b/webapps/defaults/main.yml deleted file mode 100644 index 1c25888f..00000000 --- a/webapps/defaults/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -webapps_wordpress_install: False -webapps_wordpress_version: 4.7-branch -webapps_wordpress_upstream: https://github.com/WordPress/WordPress -webapps_wordpress_upstream_default_title: "new blog Evolix SaaS" - diff --git a/webapps/evoadmin-mail/defaults/main.yml b/webapps/evoadmin-mail/defaults/main.yml new file mode 100644 index 00000000..000be699 --- /dev/null +++ b/webapps/evoadmin-mail/defaults/main.yml @@ -0,0 +1,23 @@ +--- +general_alert_email: "root@localhost" +evoadminmail_contact_email: Null +evoadminmail_bounce_email: "{{ evoadminmail_contact_email }}" + +evoadminmail_username: evoadmin-mail +evoadminmail_home_dir: "/home/{{ evoadminmail_username }}" +evoadminmail_document_root: "{{ evoadminmail_home_dir }}/www" +evoadminmail_log_dir: "{{ evoadminmail_home_dir }}/log" +evoadminmail_scripts_dir: /usr/share/scripts/ +evoadminmail_host: "evoadminmail.{{ ansible_fqdn }}" + +evoadminmail_enable_vhost: True + +evoadminmail_tpl_servername: "{{ ansible_fqdn }}" +evoadminmail_tpl_address: "{{ ansible_default_ipv4.address }}" +evoadminmail_tpl_phpmyadmin_url: Null +evoadminmail_tpl_cgi_suffix: Null +evoadminmail_tpl_signature: evoadmin +evoadminmail_tpl_mail_from: root@localhost +evoadminmail_tpl_mail_bcc: Null +evoadminmail_tpl_mail_standard: "{{ general_alert_email }}" +evoadminmail_tpl_mail_urgent: "{{ general_alert_email }}" diff --git a/webapps/evoadmin-mail/handlers/main.yml b/webapps/evoadmin-mail/handlers/main.yml new file mode 100644 index 00000000..6866dc8b --- /dev/null +++ b/webapps/evoadmin-mail/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: reload apache2 + service: + name: apache2 + state: reloaded diff --git a/webapps/evoadmin-mail/tasks/config.yml b/webapps/evoadmin-mail/tasks/config.yml new file mode 100644 index 00000000..00e342f3 --- /dev/null +++ b/webapps/evoadmin-mail/tasks/config.yml @@ -0,0 +1,17 @@ +--- + +- name: "Create /etc/evolinux" + file: + dest: "/etc/evolinux" + recurse: yes + state: directory + +#- name: Configure web-add config file +# template: +# src: web-add.conf.j2 +# dest: /etc/evolinux/web-add.conf +# +#- name: Configure web-add template file for mail +# template: +# src: web-mail.tpl.j2 +# dest: "{{ evoadminmail_scripts_dir }}/web-mail.tpl" diff --git a/webapps/evoadmin-mail/tasks/main.yml b/webapps/evoadmin-mail/tasks/main.yml new file mode 100644 index 00000000..0647bbcb --- /dev/null +++ b/webapps/evoadmin-mail/tasks/main.yml @@ -0,0 +1,19 @@ +--- + +- include: packages.yml + +- include: user.yml + +- include: config.yml + +- include: ssl.yml + +- include: web.yml + +- name: enable evoadmin-mail link in default site index + lineinfile: + dest: /var/www/index.html + state: present + regexp: "EvoAdmin-mail" + line: '
  • Interface admin mail (EvoAdmin-mail)
  • ' + insertbefore: "" diff --git a/webapps/evoadmin-mail/tasks/packages.yml b/webapps/evoadmin-mail/tasks/packages.yml new file mode 100644 index 00000000..b1b8a1dd --- /dev/null +++ b/webapps/evoadmin-mail/tasks/packages.yml @@ -0,0 +1,14 @@ +--- + +- include_role: + name: apt + tasks_from: evolix_public.yml + +- name: Install PHP packages + apt: + name: '{{ item }}' + state: present + with_items: + - php-pear + - php-log + - php-crypt-chap diff --git a/webapps/evoadmin-mail/tasks/ssl.yml b/webapps/evoadmin-mail/tasks/ssl.yml new file mode 100644 index 00000000..3dd91590 --- /dev/null +++ b/webapps/evoadmin-mail/tasks/ssl.yml @@ -0,0 +1,24 @@ +--- + + +- name: ssl-cert package is installed + apt: + name: ssl-cert + state: present + +- name: Create private key and csr for default site ({{ ansible_fqdn }}) + command: openssl req -newkey rsa:2048 -sha256 -nodes -keyout /etc/ssl/private/{{ evoadminmail_host }}.key -out /etc/ssl/{{ evoadminmail_host }}.csr -batch -subj "/CN={{ evoadminmail_host }}" + args: + creates: "/etc/ssl/private/{{ evoadminmail_host }}.key" + +- name: Adjust rights on private key + file: + path: /etc/ssl/private/{{ evoadminmail_host }}.key + owner: root + group: ssl-cert + mode: "0640" + +- name: Create certificate for default site + command: openssl x509 -req -days 3650 -sha256 -in /etc/ssl/{{ evoadminmail_host }}.csr -signkey /etc/ssl/private/{{ evoadminmail_host }}.key -out /etc/ssl/certs/{{ evoadminmail_host }}.crt + args: + creates: "/etc/ssl/certs/{{ evoadminmail_host }}.crt" diff --git a/webapps/evoadmin-mail/tasks/user.yml b/webapps/evoadmin-mail/tasks/user.yml new file mode 100644 index 00000000..5b267e72 --- /dev/null +++ b/webapps/evoadmin-mail/tasks/user.yml @@ -0,0 +1,114 @@ +--- + +- name: Create evoadmin account + user: + name: "{{ evoadminmail_username }}" + comment: "Evoadmin Web Account" + home: "{{ evoadminmail_home_dir}}" + shell: /bin/bash + password: "!" + +- name: Create log/ directory + file: + path: "{{ evoadminmail_home_dir}}/log" + state: directory + owner: "{{ evoadminmail_username }}" + group: "{{ evoadminmail_username }}" + mode: "0750" + +- name: Create www-evoadminmail group + group: + name: "www-{{ evoadminmail_username }}" + state: present + +- name: "Create www-evoadmin (Debian 9 or later)" + user: + name: "www-{{ evoadminmail_username }}" + home: "{{ evoadminmail_home_dir}}/www" + shell: /bin/bash + createhome: no + when: ansible_distribution_major_version | version_compare('9', '>=') + +- name: Install Git + apt: + name: git + state: present + +- name: "Clone evoadmin repository (Debian 9 or later)" + git: + repo: https://forge.evolix.org/evoadmin-mail.git + dest: "{{ evoadminmail_document_root}}" + version: master + update: yes + when: ansible_distribution_major_version | version_compare('9', '>=') + +- name: "Change perms on evoadminmail document root" + file: + dest: "{{ evoadminmail_document_root }}" + owner: "www-{{ evoadminmail_username }}" + group: "{{ evoadminmail_username }}" + recurse: yes + +- name: "Copy connect.php" + template: + src: connect.php.j2 + dest: "{{ evoadminmail_document_root }}/htdocs/config/connect.php" + owner: "www-{{ evoadminmail_username }}" + group: "{{ evoadminmail_username }}" + when: ldap_admin_password is defined + +- name: "Copy conf.php" + template: + src: conf.php.j2 + dest: "{{ evoadminmail_document_root }}/htdocs/config/conf.php" + owner: "www-{{ evoadminmail_username }}" + group: "{{ evoadminmail_username }}" + +- name: create a password for evoadmin user + command: "apg -n 1 -m 16 -M lcN" + register: evoadminmail_admin_password + changed_when: False + +- name: upload ldif for evoadmin user + template: + src: evoadmin.ldif.j2 + dest: /root/evolinux_evoadminmail_admin.ldif + mode: "0640" + +- name: inject config + command: slapadd -l /root/evolinux_evoadminmail_admin.ldif + +- name: create log file + file: + dest: /var/log/evoadmin-mail.log + state: touch + owner: "www-{{ evoadminmail_username }}" + group: "adm" + mode: "0640" + +- include_role: + name: remount-usr + when: evoadminmail_scripts_dir | search ("/usr") + +- name: "Create {{ evoadminmail_scripts_dir }}" + file: + dest: "{{ evoadminmail_scripts_dir }}" + # recurse: yes + mode: "0700" + state: directory + +# we use a shell command to have a "changed" thet really reflects the result. +- name: Fix permissions + shell: "chmod -R --verbose u=rwX,g=rX,o= {{ item }}" + register: command_result + changed_when: "'changed' in command_result.stdout" + # failed_when: False + with_items: + - "{{ evoadminmail_home_dir}}/www" + +#- name: Add evoadmin sudoers file +# template: +# src: sudoers.j2 +# dest: /etc/sudoers.d/evoadmin +# mode: "0600" +# validate: "visudo -cf %s" diff --git a/webapps/evoadmin-mail/tasks/web.yml b/webapps/evoadmin-mail/tasks/web.yml new file mode 100644 index 00000000..e7d915a3 --- /dev/null +++ b/webapps/evoadmin-mail/tasks/web.yml @@ -0,0 +1,30 @@ +--- + +- name: "Set custom values for PHP config (Debian 9 or later)" + ini_file: + dest: /etc/php/7.0/apache2/conf.d/zzz-evolinux-custom.ini + section: PHP + option: "disable_functions" + value: "shell-exec,system,passthru,putenv,popen,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority" + notify: reload apache2 + when: ansible_distribution_major_version | version_compare('9', '>=') + +- name: Install evoadminmail VHost + template: + src: evoadminmail.conf.j2 + dest: /etc/apache2/sites-available/evoadminmail.conf + notify: reload apache2 + +- name: Enable evoadminmail vhost + command: "a2ensite evoadminmail.conf" + register: cmd_a2ensite + changed_when: "'Enabling site' in cmd_a2ensite.stdout" + notify: reload apache2 + when: evoadminmail_enable_vhost + +- name: Disable evoadminmail vhost + command: "a2dissite evoadminmail.conf" + register: cmd_a2dissite + changed_when: "'Disabling site' in cmd_a2dissite.stdout" + notify: reload apache2 + when: not evoadminmail_enable_vhost diff --git a/webapps/evoadmin-mail/templates/conf.php.j2 b/webapps/evoadmin-mail/templates/conf.php.j2 new file mode 100644 index 00000000..bac22bfd --- /dev/null +++ b/webapps/evoadmin-mail/templates/conf.php.j2 @@ -0,0 +1,56 @@ + + * @version 1.0 + */ + +define("LDAP_URI","ldap://127.0.0.1"); +$ldap_servers = array('ldap://127.0.0.1'); +define("LDAP_BASE","{{ ldap_suffix }}"); +define("LDAP_ADMIN_DN","cn=admin,{{ ldap_suffix }}"); +define("LDAP_ADMIN_PASS","{{ ldap_admin_password.stdout }}"); + +define("SUDOBIN","/usr/bin/sudo"); +define("SUDOSCRIPT","/usr/share/scripts/evoadmin.sh"); +define("SUDOPASS","xxxxxx"); + +define('SERVEUR','localhost'); +define('SERVEURPORT',3306); +define('BASE','horde'); +define('NOM', 'horde'); +define('PASSE', 'xxxx'); + +?> diff --git a/webapps/evoadmin-mail/templates/evoadmin.ldif.j2 b/webapps/evoadmin-mail/templates/evoadmin.ldif.j2 new file mode 100644 index 00000000..389fdff9 --- /dev/null +++ b/webapps/evoadmin-mail/templates/evoadmin.ldif.j2 @@ -0,0 +1,12 @@ +dn: uid=evoadmin,{{ ldap_suffix }} +uid: evoadmin +cn: Evoadmin ADM +uidNumber: 4242 +gidNumber: 4242 +homeDirectory: /dev/null +isAdmin: TRUE +mailacceptinggeneralid: evoadmin@{{ ansible_fqdn }} +objectClass: mailAccount +objectClass: organizationalRole +objectClass: posixAccount +userPassword: {{ evoadminmail_admin_password.stdout }} diff --git a/webapps/evoadmin-mail/templates/evoadminmail.conf.j2 b/webapps/evoadmin-mail/templates/evoadminmail.conf.j2 new file mode 100644 index 00000000..026fe00d --- /dev/null +++ b/webapps/evoadmin-mail/templates/evoadminmail.conf.j2 @@ -0,0 +1,58 @@ + + ServerName {{ evoadminmail_host }} + Redirect permanent / https://{{ evoadminmail_host }}/ + + + + + # FQDN principal + ServerName {{ evoadminmail_host }} + #ServerAlias {{ evoadminmail_host }} + + # Repertoire principal + DocumentRoot {{ evoadminmail_document_root }}/htdocs/ + + # SSL + SSLEngine on + SSLCertificateFile /etc/ssl/certs/{{ evoadminmail_host }}.crt + SSLCertificateKeyFile /etc/ssl/private/{{ evoadminmail_host }}.key + SSLProtocol all -SSLv2 -SSLv3 + + # Propriete du repertoire + + #Options Indexes SymLinksIfOwnerMatch + Options SymLinksIfOwnerMatch + AllowOverride AuthConfig Limit FileInfo + Require all granted + + + # user - group (thanks to sesse@debian.org) + AssignUserID www-{{ evoadminmail_username }} {{ evoadminmail_username }} + + # LOG + CustomLog /var/log/apache2/access.log combined + CustomLog {{ evoadminmail_log_dir }}/access.log combined + ErrorLog {{ evoadminmail_log_dir }}/error.log + + # AWSTATS + SetEnv AWSTATS_FORCE_CONFIG {{ evoadminmail_username }} + + # REWRITE + UseCanonicalName On + RewriteEngine On + RewriteCond %{HTTP_HOST} !^{{ evoadminmail_host }}$ + RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [L,R] + + # PHP + #php_admin_flag engine off + #AddType text/html .html + #php_admin_flag display_errors On + #php_flag short_open_tag On + #php_flag register_globals On + #php_admin_value memory_limit 256M + #php_admin_value max_execution_time 60 + #php_admin_value upload_max_filesize 8M + #php_admin_flag allow_url_fopen Off + php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f www-{{ evoadminmail_username }}" + php_admin_value open_basedir "none" + diff --git a/webapps/evoadmin-mail/templates/sudoers.j2 b/webapps/evoadmin-mail/templates/sudoers.j2 new file mode 100644 index 00000000..4dfd71c1 --- /dev/null +++ b/webapps/evoadmin-mail/templates/sudoers.j2 @@ -0,0 +1,3 @@ +User_Alias EVOADMIN = www-evoadmin +Cmnd_Alias EVOADMIN_WEB = {{ evoadmin_scripts_dir | mandatory }}/web-*.sh, {{ evoadmin_scripts_dir | mandatory }}/ftpadmin.sh +EVOADMIN ALL=NOPASSWD: EVOADMIN_WEB diff --git a/webapps/evoadmin-mail/templates/web-add.conf.j2 b/webapps/evoadmin-mail/templates/web-add.conf.j2 new file mode 100644 index 00000000..86eabd29 --- /dev/null +++ b/webapps/evoadmin-mail/templates/web-add.conf.j2 @@ -0,0 +1,2 @@ +CONTACT_MAIL="{{ evoadmin_contact_email or general_alert_email | mandatory }}" +WWWBOUNCE_MAIL="{{ evoadmin_bounce_email or general_alert_email | mandatory }}" diff --git a/webapps/evoadmin-mail/templates/web-mail.tpl.j2 b/webapps/evoadmin-mail/templates/web-mail.tpl.j2 new file mode 100644 index 00000000..262995c3 --- /dev/null +++ b/webapps/evoadmin-mail/templates/web-mail.tpl.j2 @@ -0,0 +1,86 @@ +From: {{ evoadmin_tpl_mail_from }} +To: RCPTTO +Bcc: {{ evoadmin_tpl_mail_bcc }} +Subject: Parametres hebergement web : LOGIN + +Bonjour, + +Votre compte d'hebergement web a ete cree. + +********************************** +* CONNEXION SFTP/SSH +********************************** + +NOM DU SERVEUR : {{ evoadmin_tpl_servername }} +USER : LOGIN +PASSWORD : PASSE1 + +***************************************** +* Details sur l'environnement Apache/PHP +***************************************** + +URL du site : +http://{{ evoadmin_tpl_servername }} + +URL des stats : +http://{{ evoadmin_tpl_servername }}/cgi-RANDOM/awstats.pl +(acces par IP ou login a demander !) + +Repertoire de connexion : HOME_DIR/LOGIN/ +Repertoire pour site web : HOME_DIR/LOGIN/www/ + +Apache/PHP tourne en www-LOGIN:LOGIN c'est-a-dire qu'il a acces +uniquement *en lecture* aux differents fichiers/repertoires +(a condition d'avoir 'g=rx' sur les repertoires et 'g=r' sur les +fichiers ce qui est le comportement par defaut). + +Lorsqu'on a besoin d'autoriser *l'ecriture* pour certains +fichiers/repertoires, il suffit d'ajouter le droit 'g+w'. + +*********************************** +* MySQL +*********************************** + +SERVEUR : 127.0.0.1 +PORT DU SERVEUR : 3306 +USER : LOGIN +PASSWORD : PASSE2 +NOM BASE : DBNAME +URL interface d'admin : +{{ evoadmin_tpl_phpmyadmin_url }} + +*********************************** +* Rappels divers +*********************************** + +Votre nom de domaine doit etre configure pour pointer +sur l'adresse IP {{ evoadmin_tpl_address }} (enregistrement DNS A) +ou etre un alias de {{ evoadmin_tpl_servername }} (enregistrement DNS CNAME). + +Si vous avez besoin de faire des tests, vous devez +ajouter la ligne suivante au fichier "/etc/hosts" sous Linux/Unix +ou au fichier "system32\drivers\etc\hosts" sous Windows NT/XP : +{{ evoadmin_tpl_address }} {{ evoadmin_tpl_servername }} + +Attention, par defaut, toutes les connexions vers l'exterieur +sont bloquees. Si vous avez besoin de recuperer des donnees +a l'exterieur (flux RSS, BDD externe, etc.), contactez nous +afin de mettre en oeuvre les autorisations necessaires. + +Afin de securiser au maximum le serveur, certaines URL +particulieres sont non autorisees pour eviter diverses +attaques (XSS, robots, trojans, injections, etc.). +Exemple d'URL refusee : +http://{{ evoadmin_tpl_servername }}/cmd32.exe +En cas de soucis avec votre application, prevenez-nous. + +Si vous desirez mettre en place des parametres particuliers +pour votre site (PHP, etc.) ou pour tout autre demande (scripts en crontab, +etc.), n'hesitez pas a nous contacter a l'adresse +{{ evoadmin_tpl_mail_standard }} (ou {{ evoadmin_tpl_mail_urgent }} si votre demande est +urgente). + + +Cordialement, +-- +{{ evoadmin_tpl_signature }} diff --git a/webapps/evoadmin-web/defaults/main.yml b/webapps/evoadmin-web/defaults/main.yml index 58200cf1..c57c3b54 100644 --- a/webapps/evoadmin-web/defaults/main.yml +++ b/webapps/evoadmin-web/defaults/main.yml @@ -6,7 +6,7 @@ evoadmin_bounce_email: "{{ evoadmin_contact_email }}" evoadmin_home_dir: "/home/{{ evoadmin_username }}" evoadmin_document_root: "{{ evoadmin_home_dir }}/www" evoadmin_log_dir: "{{ evoadmin_home_dir }}/log" -evoadmin_scripts_dir: /usr/share/scripts/evoadmin/ +evoadmin_scripts_dir: /usr/share/scripts/evoadmin evoadmin_host: "evoadmin.{{ ansible_fqdn }}" evoadmin_username: evoadmin diff --git a/webapps/evoadmin-web/files/evolinux.conf.diff b/webapps/evoadmin-web/files/ftp/evolinux.conf.diff similarity index 100% rename from webapps/evoadmin-web/files/evolinux.conf.diff rename to webapps/evoadmin-web/files/ftp/evolinux.conf.diff diff --git a/webapps/evoadmin-web/meta/main.yml b/webapps/evoadmin-web/meta/main.yml new file mode 100644 index 00000000..82440b08 --- /dev/null +++ b/webapps/evoadmin-web/meta/main.yml @@ -0,0 +1,18 @@ +galaxy_info: + author: Evolix + description: Installation of evoadmin-web + + issue_tracker_url: https://forge.evolix.org/projects/ansible-roles/issues + + license: GPLv2 + + min_ansible_version: 2.2 + + platforms: + - name: Debian + versions: + - jessie + - stretch + +dependencies: + - proftpd diff --git a/webapps/evoadmin-web/tasks/ftp.yml b/webapps/evoadmin-web/tasks/ftp.yml index 83913d01..a78150a1 100644 --- a/webapps/evoadmin-web/tasks/ftp.yml +++ b/webapps/evoadmin-web/tasks/ftp.yml @@ -1,25 +1,12 @@ --- -- name: Verify if proftpd has evolinux config file - stat: - path: /etc/proftpd/conf.d/z-evolinux.conf - register: proftpd_config +- name: patch must be installed + apt: + name: patch + state: installed -- block: - - name: Patch ProFTPd config file - patch: - remote_src: no - src: evolinux.conf.diff - dest: /etc/proftpd/conf.d/z-evolinux.conf - - # Why 440? Because should be edited with ftpasswd. - # So, readonly when opened with vim. - # Then readable by group. - - name: Create /etc/proftpd/vpasswd file in 0440 mode - file: - state: touch - path: /etc/proftpd/vpasswd - mode: "0440" - owner: root - group: root - when: proftpd_config.stat.exists +- name: Patch ProFTPd config file + patch: + remote_src: no + src: ftp/evolinux.conf.diff + dest: /etc/proftpd/conf.d/z-evolinux.conf diff --git a/webapps/evoadmin-web/tasks/packages.yml b/webapps/evoadmin-web/tasks/packages.yml index e0b1fe05..79d1e312 100644 --- a/webapps/evoadmin-web/tasks/packages.yml +++ b/webapps/evoadmin-web/tasks/packages.yml @@ -4,8 +4,6 @@ name: apt tasks_from: evolix_public.yml -- meta: flush_handlers - - name: Install PHP packages apt: name: '{{ item }}' diff --git a/webapps/evoadmin-web/tasks/remount_usr_rw.yml b/webapps/evoadmin-web/tasks/remount_usr_rw.yml deleted file mode 100644 index 8c51aee2..00000000 --- a/webapps/evoadmin-web/tasks/remount_usr_rw.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Get mount options for partitions - shell: "mount | grep 'on /usr type'" - args: - warn: no - register: mount - changed_when: False - failed_when: False - when: not ansible_check_mode - -- name: Remount /usr if it is a partition and it is not mounted in rw - command: "mount -o remount,rw /usr" - when: mount.rc == 0 and not mount.stdout_lines.0 | search("rw") - args: - warn: no diff --git a/webapps/evoadmin-web/tasks/user.yml b/webapps/evoadmin-web/tasks/user.yml index c5e5a35b..4070a52a 100644 --- a/webapps/evoadmin-web/tasks/user.yml +++ b/webapps/evoadmin-web/tasks/user.yml @@ -24,7 +24,7 @@ name: www-evoadmin when: ansible_distribution_major_version | version_compare('9', '>=') -- name: Install Git +- name: Git is needed to clone the evoadmin repository apt: name: git state: present @@ -35,8 +35,6 @@ dest: "{{ evoadmin_document_root}}" version: jessie update: no - # Warning: Need sudo! - become_user: "{{ evoadmin_username }}" when: ansible_distribution_release == "jessie" - name: "Clone evoadmin repository (Debian 9 or later)" @@ -45,11 +43,17 @@ dest: "{{ evoadmin_document_root}}" version: master update: yes - # Warning: Need sudo! - become_user: "{{ evoadmin_username }}" when: ansible_distribution_major_version | version_compare('9', '>=') -- include: remount_usr_rw.yml +- name: Change ownership on git repository + file: + dest: "{{ evoadmin_document_root}}" + owner: "{{ evoadmin_username }}" + group: "{{ evoadmin_username }}" + recurse: yes + +- include_role: + name: remount-usr when: evoadmin_scripts_dir | search ("/usr") - name: "Create {{ evoadmin_scripts_dir }}" @@ -66,12 +70,12 @@ # we use a shell command to have a "changed" thet really reflects the result. - name: Fix permissions - shell: "chmod -R --verbose u=rwX,g=rX,o= {{ item }}" + command: "chmod -R --verbose u=rwX,g=rX,o= {{ evoadmin_document_root }}" register: command_result changed_when: "'changed' in command_result.stdout" # failed_when: False - with_items: - - "{{ evoadmin_home_dir}}/www" + args: + warn: no - name: Add evoadmin sudoers file template: diff --git a/webapps/evoadmin-web/tasks/web.yml b/webapps/evoadmin-web/tasks/web.yml index 0944c2cd..59c41582 100644 --- a/webapps/evoadmin-web/tasks/web.yml +++ b/webapps/evoadmin-web/tasks/web.yml @@ -6,7 +6,7 @@ section: PHP option: "disable_functions" value: "shell-exec,system,passthru,putenv,popen" - notify: reload apache + notify: reload apache2 when: ansible_distribution_release == "jessie" - name: "Set custom values for PHP config (Debian 9 or later)" @@ -15,7 +15,7 @@ section: PHP option: "disable_functions" value: "shell-exec,system,passthru,putenv,popen" - notify: reload apache + notify: reload apache2 when: ansible_distribution_major_version | version_compare('9', '>=') - name: Install evoadmin VHost diff --git a/webapps/evoadmin-web/templates/web-mail.tpl.j2 b/webapps/evoadmin-web/templates/web-mail.tpl.j2 index 262995c3..57c92779 100644 --- a/webapps/evoadmin-web/templates/web-mail.tpl.j2 +++ b/webapps/evoadmin-web/templates/web-mail.tpl.j2 @@ -20,10 +20,10 @@ PASSWORD : PASSE1 ***************************************** URL du site : -http://{{ evoadmin_tpl_servername }} +http://SERVERNAME URL des stats : -http://{{ evoadmin_tpl_servername }}/cgi-RANDOM/awstats.pl +http://SERVERNAME/cgi-RANDOM/awstats.pl (acces par IP ou login a demander !) Repertoire de connexion : HOME_DIR/LOGIN/ @@ -60,7 +60,7 @@ ou etre un alias de {{ evoadmin_tpl_servername }} (enregistrement DNS CNAME). Si vous avez besoin de faire des tests, vous devez ajouter la ligne suivante au fichier "/etc/hosts" sous Linux/Unix ou au fichier "system32\drivers\etc\hosts" sous Windows NT/XP : -{{ evoadmin_tpl_address }} {{ evoadmin_tpl_servername }} +{{ evoadmin_tpl_address }} SERVERNAME Attention, par defaut, toutes les connexions vers l'exterieur sont bloquees. Si vous avez besoin de recuperer des donnees @@ -71,7 +71,7 @@ Afin de securiser au maximum le serveur, certaines URL particulieres sont non autorisees pour eviter diverses attaques (XSS, robots, trojans, injections, etc.). Exemple d'URL refusee : -http://{{ evoadmin_tpl_servername }}/cmd32.exe +http://SERVERNAME/cmd32.exe En cas de soucis avec votre application, prevenez-nous. Si vous desirez mettre en place des parametres particuliers diff --git a/webapps/handlers/main.yml b/webapps/handlers/main.yml deleted file mode 100644 index b1d39d12..00000000 --- a/webapps/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for webapps diff --git a/webapps/roundcube/defaults/main.yml b/webapps/roundcube/defaults/main.yml new file mode 100644 index 00000000..5e0c1a81 --- /dev/null +++ b/webapps/roundcube/defaults/main.yml @@ -0,0 +1,4 @@ +--- +roundcube_host: "roundcube.{{ ansible_fqdn }}" +roundcube_imap_host: "localhost" +roundcube_imap_port: 143 diff --git a/webapps/roundcube/handlers/main.yml b/webapps/roundcube/handlers/main.yml new file mode 100644 index 00000000..bdba6e6b --- /dev/null +++ b/webapps/roundcube/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart imapproxy + systemd: + name: imapproxy + state: restarted diff --git a/webapps/roundcube/tasks/main.yml b/webapps/roundcube/tasks/main.yml new file mode 100644 index 00000000..9eac3dd9 --- /dev/null +++ b/webapps/roundcube/tasks/main.yml @@ -0,0 +1,114 @@ +--- +- name: configure roundcube-core + debconf: + name: roundcube-core + question: "{{ item.key }}" + value: "{{ item.value }}" + vtype: "{{ item.type }}" + with_items: + - { key: 'roundcube/database-type', type: 'select', value: 'sqlite3' } + - { key: 'roundcube/db/basepath', type: 'string', value: '/var/lib/roundcube/' } + tags: + - roundcube + +- name: install Roundcube + apt: + name: "{{ item }}" + state: present + with_items: + - imapproxy + - roundcube + - roundcube-sqlite3 + - roundcube-plugins + - php-net-sieve + - php-zip + tags: + - roundcube + +- name: configure imapproxy imap host + lineinfile: + dest: /etc/imapproxy.conf + regexp: "^server_hostname" + line: "server_hostname {{ roundcube_imap_host }}" + notify: restart imapproxy + tags: + - roundcube + +- name: configure imapproxy imap port + lineinfile: + dest: /etc/imapproxy.conf + regexp: "^server_port" + line: "server_port {{ roundcube_imap_port }}" + notify: reload imapproxy + tags: + - roundcube + +- name: enable and start imapproxy + service: + name: imapproxy + state: started + enabled: True + tags: + - roundcube + +- name: configure roundcube imap host + lineinfile: + dest: /etc/roundcube/config.inc.php + regexp: "\\$config\\['default_host'\\]" + line: "$config['default_host'] = array('127.0.0.1');" + tags: + - roundcube + +- name: configure roudcube imap port + lineinfile: + dest: /etc/roundcube/config.inc.php + regexp: "\\$config\\['default_port'\\]" + insertafter: "\\$config\\['default_host'\\]" + line: "$config['default_port'] = 1143;" + tags: + - roundcube + +- name: configure managesieve plugin + copy: + src: /usr/share/roundcube/plugins/managesieve/config.inc.php.dist + dest: /etc/roundcube/plugins/managesieve/config.inc.php + mode: "0644" + remote_src: True + tags: + - roundcube + +- name: enable default plugins + replace: + dest: /etc/roundcube/config.inc.php + regexp: "^\\$config\\['plugins'\\] = array\\($" + replace: "$config['plugins'] = array('zipdownload','managesieve'" + tags: + - roundcube + +- name: deploy roundcube vhost + template: + src: apache2.conf.j2 + dest: /etc/apache2/sites-available/rouncube.conf + mode: "0640" + notify: reload apache2 + tags: + - roundcube + +- name: enable roundcube vhost + file: + src: /etc/apache2/sites-available/rouncube.conf + dest: /etc/apache2/sites-enabled/rouncube.conf + state: link + notify: reload apache2 + tags: + - roundcube + +- name: enable roundcube link in default site index + lineinfile: + dest: /var/www/index.html + state: present + regexp: "Webmail" + line: '
  • Webmail
  • ' + insertbefore: "" + tags: + - roundcube diff --git a/webapps/roundcube/templates/apache2.conf.j2 b/webapps/roundcube/templates/apache2.conf.j2 new file mode 100644 index 00000000..47865c01 --- /dev/null +++ b/webapps/roundcube/templates/apache2.conf.j2 @@ -0,0 +1,46 @@ + + ServerName {{ roundcube_host }} + Redirect permanent / https://{{ roundcube_host }} + + + + + # FQDN principal + ServerName {{ roundcube_host }} + + # Repertoire principal + DocumentRoot /var/lib/roundcube/ + + # Return 503 if imapproxy doesn't run + + Redirect 503 / + + + Include /etc/roundcube/apache.conf + + # LOG + CustomLog /var/log/apache2/access.log vhost_combined + CustomLog /var/lib/roundcube/logs/access.log combined + ErrorLog /var/lib/roundcube/logs/error.log + + # REWRITE + UseCanonicalName On + RewriteEngine On + RewriteCond %{HTTP_HOST} !^{{ roundcube_host }}$ + RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [L,R] + + # PHP + #php_admin_flag engine off + #AddType text/html .html + #php_admin_flag display_errors On + #php_flag short_open_tag On + #php_flag register_globals On + #php_admin_value memory_limit 256M + #php_admin_value max_execution_time 60 + #php_admin_value upload_max_filesize 8M + #php_admin_flag allow_url_fopen Off + php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f www-roundcube" + php_admin_value error_log "/home/roundcube/log/php.log" + #php_admin_value open_basedir "/usr/share/php:/home/roundcube:/tmp" + + diff --git a/webapps/tasks/main.yml b/webapps/tasks/main.yml deleted file mode 100644 index a86da0fd..00000000 --- a/webapps/tasks/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- - -- include: wordpress.yml - when: webapps_wordpress_install diff --git a/webapps/tasks/wordpress.yml b/webapps/tasks/wordpress.yml deleted file mode 100644 index e85433c1..00000000 --- a/webapps/tasks/wordpress.yml +++ /dev/null @@ -1,48 +0,0 @@ - #- name: Init global variables - # include: './tasks/var_common.yml' - - - name: init dir_wpcli - set_fact: dir_wpcli="{{ dir }}/wp-cli" - - - debug: var=dir_wpcli - when: debug_mode - tags: debug_mode - - - name: Git clone Wordpress repository - include: './tasks/git.yml' - vars: - service_git: WordPress - url_git: "{{ webapps_wordpress_upstream }}" - dest_git: "{{ dir_www }}" - version_git: "{{ webapps_wordpress_version }}" - - - name: Creation directory wp-cli - file: > - path: "{{ dir_wpcli }}" - state: directory - - - name: Download wp-cli.phar - include: './tasks/download.yml' - vars: - url: 'https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar' - dest: "{{ dir_wpcli }}" - - - name: Configuration for db - shell: > - php wp-cli.phar core config --dbname="{{ db_name }}" --dbuser="{{ db_user }}" --dbpass="{{ db_pwd }}" --dbhost="{{ db_host }}" --path="{{ dir_www }}" - chdir: "{{ dir_wpcli }}" - - - name: Wordpress site installation - shell: > - php wp-cli.phar core install --url="{{ host }}" --title="{{ site_title }}" --admin_user="admin" --admin_password="{{ admin_pwd }}" --admin_email="{{ user }}@{{ ansible_fqdn }}" --skip-email --path="{{ dir_www }}" - chdir: "{{ dir_wpcli }}" - - - name: Init variables to sending the email about the installation - include: './tasks/var_email_install.yml' - vars: - admin_user: 'admin' - type: 'Installation' - - - name: Send email - include: './tasks/email.yml' - diff --git a/webapps/vars/main.yml b/webapps/vars/main.yml deleted file mode 100644 index 5ec52e44..00000000 --- a/webapps/vars/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# vars file for webapps diff --git a/webapps/wordpress/defaults/main.yml b/webapps/wordpress/defaults/main.yml new file mode 100644 index 00000000..f2508aff --- /dev/null +++ b/webapps/wordpress/defaults/main.yml @@ -0,0 +1,7 @@ +--- +wordpress_wpcli: "php {{ ansible_env.HOME }}/bin/wp-cli.phar --path={{ ansible_env.HOME }}/www" +wordpress_version: 'latest' +wordpress_plugins: ['wp-fail2ban'] +wordpress_host: "{{ ansible_fqdn }}" +wordpress_title: "Wordpress Saas Evolix" +wordpress_email: "root@localhost" diff --git a/webapps/meta/main.yml b/webapps/wordpress/meta/main.yml similarity index 90% rename from webapps/meta/main.yml rename to webapps/wordpress/meta/main.yml index a8204bf9..73c6e08f 100644 --- a/webapps/meta/main.yml +++ b/webapps/wordpress/meta/main.yml @@ -1,6 +1,6 @@ galaxy_info: author: Evolix - description: your description + description: Install Wordpress site issue_tracker_url: https://forge.evolix.org/projects/ansible-roles/issues diff --git a/webapps/wordpress/tasks/main.yml b/webapps/wordpress/tasks/main.yml new file mode 100644 index 00000000..d8a4598b --- /dev/null +++ b/webapps/wordpress/tasks/main.yml @@ -0,0 +1,103 @@ +--- +- name: Create bin dir + file: + state: directory + dest: "{{ ansible_env.HOME }}/bin" + mode: "0750" + +- name: Download wp-cli + get_url: + url: "https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar" + dest: "{{ ansible_env.HOME }}/bin/wp-cli.phar" + mode: "0750" + +- name: Download Wordpress + shell: '{{ wordpress_wpcli }} core download --locale=fr_FR --version={{ wordpress_version }}' + args: + creates: "{{ ansible_env.HOME }}/www/index.php" + +- name: Retrieve .my.cnf + fetch: + src: "{{ ansible_env.HOME }}/.my.cnf" + dest: "/tmp/wordpress-{{ ansible_user }}.cnf" + flat: yes + +- name: Generate random password + command: apg -n1 -m 12 -M LCN + register: shell_password + changed_when: false + +- name: Read mysql config from .my.cnf + set_fact: + db_host: "{{ lookup('ini', 'host section=client file=/tmp/wordpress-{{ ansible_user }}.cnf default=127.0.0.1') }}" + db_user: "{{ lookup('ini', 'user section=client file=/tmp/wordpress-{{ ansible_user }}.cnf default={{ ansible_user }}') }}" + db_pwd: "{{ lookup('ini', 'password section=client file=/tmp/wordpress-{{ ansible_user }}.cnf') }}" + db_name: "{{ lookup('ini', 'database section=mysql file=/tmp/wordpress-{{ ansible_user }}.cnf default={{ ansible_user }}') }}" + admin_pwd: "{{ shell_password.stdout }}" + +- name: Remove local .my.cnf + file: + path: "/tmp/wordpress-{{ ansible_user }}.cnf" + state: absent + delegate_to: localhost + +- name: Configure Wordpress (wp-config.php) + shell: '{{ wordpress_wpcli }} core config --dbhost={{ db_host }} --dbuser={{ db_user }} --dbpass={{ db_pwd }} --dbname={{ db_name }}' + args: + creates: "{{ ansible_env.HOME }}/www/wp-config.php" + +- name: Configure site + shell: '{{ wordpress_wpcli }} core install --url={{ wordpress_host | quote }} --title={{ wordpress_title | quote }} --admin_user=admin --admin_password="{{ admin_pwd | quote }}" --admin_email={{ wordpress_email }} --skip-email' + changed_when: false + +- name: Check if Wordpress is up to date + shell: '{{ wordpress_wpcli }} core check-update | grep -q Success' + register: check_version + check_mode: no + failed_when: false + changed_when: check_version.rc + +- name: Update Wordpress + shell: '{{ wordpress_wpcli }} core update --version={{ wordpress_version }}' + args: + removes: "{{ ansible_env.HOME }}/www/index.php" + when: check_version.rc + +- name: Install default plugin + shell: '{{ wordpress_wpcli }} plugin is-installed {{ item }} || {{ wordpress_wpcli }} plugin install {{ item }}' + changed_when: false + with_items: "{{ wordpress_plugins }}" + +- name: Update default plugins + shell: '{{ wordpress_wpcli }} plugin is-installed {{ item }} && {{ wordpress_wpcli }} plugin update {{ item }}' + changed_when: false + with_items: "{{ wordpress_plugins }}" + +- name: Activate default plugins + shell: '{{ wordpress_wpcli }} plugin is-installed {{ item }} && {{ wordpress_wpcli }} plugin activate {{ item }}' + changed_when: false + with_items: "{{ wordpress_plugins }}" + +- name: Send a summary mail + mail: + host: 'localhost' + port: 25 + to: "{{ wordpress_email }}" + from: "{{ ansible_user }}@{{ ansible_fqdn }}" + subject: "Nouveau site Wordpress {{ ansible_user }}" + charset: "utf-8" + body: | + Votre nouveau site WordPress a bien été installé à l’adresse : + + http://{{ wordpress_host }} + + Vous pouvez vous y connecter en tant qu’administrateur avec les informations suivantes : + + Identifiant : admin + Mot de passe : {{ admin_pwd }} + Connectez-vous ici : http://{{ wordpress_host }}/wp-login.php + + Nous espérons que vous aimerez votre nouveau site ! Merci à vous ! + -- + Équipe Evolix + Evolix - Hébergement et Infogérance Open Source http://www.evolix.fr/