Merge branch 'unstable' into stable
This commit is contained in:
commit
9038beefd1
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
admin_users: {}
|
||||
admin_users_group: adm
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
|
||||
- include: user.yml
|
||||
|
||||
- include: profile.yml
|
||||
|
||||
- include: ssh.yml
|
||||
|
||||
- include: sudo.yml
|
||||
|
||||
- meta: flush_handlers
|
|
@ -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 != {}
|
|
@ -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
|
|
@ -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', '>=')
|
5
amavis/handlers/main.yml
Normal file
5
amavis/handlers/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: restart amavis
|
||||
service:
|
||||
name: amavis
|
||||
state: restarted
|
19
amavis/tasks/main.yml
Normal file
19
amavis/tasks/main.yml
Normal file
|
@ -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
|
57
amavis/templates/amavis.conf.j2
Normal file
57
amavis/templates/amavis.conf.j2
Normal file
|
@ -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
|
60
amazon-ec2/README
Normal file
60
amazon-ec2/README
Normal file
|
@ -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.
|
62
amazon-ec2/amazon-ec2-evolinux.yml
Normal file
62
amazon-ec2/amazon-ec2-evolinux.yml
Normal file
|
@ -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
|
135
amazon-ec2/defaults/main.yml
Normal file
135
amazon-ec2/defaults/main.yml
Normal file
|
@ -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
|
36
amazon-ec2/tasks/create-instance.yml
Normal file
36
amazon-ec2/tasks/create-instance.yml
Normal file
|
@ -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}}"
|
5
amazon-ec2/tasks/post-install.yml
Normal file
5
amazon-ec2/tasks/post-install.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: Remove admin user
|
||||
user:
|
||||
name: admin
|
||||
state: absent
|
20
amazon-ec2/tasks/setup.yml
Normal file
20
amazon-ec2/tasks/setup.yml
Normal file
|
@ -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}}"
|
|
@ -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`).
|
||||
|
|
|
@ -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: []
|
||||
|
|
18
apache/files/save_apache_status.sh
Normal file
18
apache/files/save_apache_status.sh
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
Require all denied
|
||||
Include /etc/apache2/ipaddr_whitelist.conf
|
||||
</Directory>
|
||||
<Directory /usr/lib/munin/cgi/>
|
||||
Options -Indexes
|
||||
# munin-cgi-graph, used for zooming on graphs.
|
||||
ScriptAlias /munin-cgi/munin-cgi-graph /usr/lib/munin/cgi/munin-cgi-graph
|
||||
<Location /munin-cgi/munin-cgi-graph>
|
||||
Options +ExecCGI
|
||||
Require all denied
|
||||
Include /etc/apache2/ipaddr_whitelist.conf
|
||||
</Directory>
|
||||
</Location>
|
||||
|
||||
# For CGI Scripts. We need to set Directory directive as ScriptAlias take precedence.
|
||||
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
|
||||
|
|
|
@ -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`) ;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
- name: apt update
|
||||
apt:
|
||||
update_cache: yes
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
5
clamav/handlers/main.yml
Normal file
5
clamav/handlers/main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
- name: restart clamav
|
||||
service:
|
||||
name: clamav-daemon
|
||||
state: restarted
|
3
clamav/meta/main.yml
Normal file
3
clamav/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- { role: amavis }
|
111
clamav/tasks/main.yml
Normal file
111
clamav/tasks/main.yml
Normal file
|
@ -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
|
36
dovecot/.kitchen.yml
Normal file
36
dovecot/.kitchen.yml
Normal file
|
@ -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
|
11
dovecot/README.md
Normal file
11
dovecot/README.md
Normal file
|
@ -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`.
|
2
dovecot/defaults/main.yml
Normal file
2
dovecot/defaults/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
dovecot_foo: bar
|
126
dovecot/files/munin_plugin
Executable file
126
dovecot/files/munin_plugin
Executable file
|
@ -0,0 +1,126 @@
|
|||
#! /bin/bash
|
||||
#
|
||||
# Munin Plugin
|
||||
# to count logins to your dovecot mailserver
|
||||
#
|
||||
# Created by Dominik Schulz <lkml@ds.gauner.org>
|
||||
# http://developer.gauner.org/munin/
|
||||
# Contributions by:
|
||||
# - Stephane Enten <tuf@delyth.net>
|
||||
# - Steve Schnepp <steve.schnepp@pwkf.org>
|
||||
#
|
||||
# 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
|
10
dovecot/handlers/main.yml
Normal file
10
dovecot/handlers/main.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
- name: restart dovecot
|
||||
service:
|
||||
name: dovecot
|
||||
state: restarted
|
||||
|
||||
- name: reload dovecot
|
||||
service:
|
||||
name: dovecot
|
||||
state: reloaded
|
68
dovecot/tasks/main.yml
Normal file
68
dovecot/tasks/main.yml
Normal file
|
@ -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
|
20
dovecot/tasks/munin.yml
Normal file
20
dovecot/tasks/munin.yml
Normal file
|
@ -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
|
36
dovecot/templates/z-evolinux-defaults.conf.j2
Normal file
36
dovecot/templates/z-evolinux-defaults.conf.j2
Normal file
|
@ -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
|
|
@ -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'
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
9
elasticsearch/tasks/logs.yml
Normal file
9
elasticsearch/tasks/logs.yml
Normal file
|
@ -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"
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
- include: tmpdir.yml
|
||||
|
||||
- include: logs.yml
|
||||
|
||||
- include: plugin_head.yml
|
||||
when: elasticsearch_plugin_head
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
14
elasticsearch/templates/elasticsearch-head.service.j2
Normal file
14
elasticsearch/templates/elasticsearch-head.service.j2
Normal file
|
@ -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
|
9
elasticsearch/templates/rotate_elasticsearch_logs.j2
Normal file
9
elasticsearch/templates/rotate_elasticsearch_logs.j2
Normal file
|
@ -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
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <<EOT
|
||||
Usage: ${PROGNAME} NAME
|
||||
NAME must be correspond to :
|
||||
- a CSR in ${CSR_DIR}/NAME.csr
|
||||
- a KEY in ${SSL_KEY_DIR}/NAME.key
|
||||
|
||||
If env variable TEST=1, certbot is run in staging mode
|
||||
If env variable DRY_RUN=1, certbot is run in dry-run mode
|
||||
If env variable QUIET=1, no message is output
|
||||
If env variable VERBOSE=1, debug messages are output
|
||||
EOT
|
||||
}
|
||||
|
||||
mkconf_apache() {
|
||||
[ -f "/etc/apache2/ssl/${vhost}.conf" ] && sed -i "s~^SSLCertificateFile.*$~SSLCertificateFile $CRT_DIR/${vhost}/live/fullchain.pem~" "/etc/apache2/ssl/${vhost}.conf"
|
||||
apache2ctl -t 2>/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}
|
||||
|
|
28
evoacme/files/hooks/reload_apache
Executable file
28
evoacme/files/hooks/reload_apache
Executable file
|
@ -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
|
32
evoacme/files/hooks/reload_dovecot
Executable file
32
evoacme/files/hooks/reload_dovecot
Executable file
|
@ -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
|
28
evoacme/files/hooks/reload_nginx
Executable file
28
evoacme/files/hooks/reload_nginx
Executable file
|
@ -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
|
32
evoacme/files/hooks/reload_postfix
Executable file
32
evoacme/files/hooks/reload_postfix
Executable file
|
@ -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
|
|
@ -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 <vlaborie@evolix.fr>
|
||||
# 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 <<EOT
|
||||
Usage: ${PROGNAME} VHOST DOMAIN...
|
||||
VHOST must correspond to an Apache or Nginx enabled VHost
|
||||
If VHOST ends with ".conf" it is stripped,
|
||||
then files are seached at those paths:
|
||||
- /etc/apache2/sites-enables/VHOST.conf
|
||||
- /etc/nginx/sites-enabled/VHOST.conf
|
||||
- /etc/nginx/sites-enabled/VHOST
|
||||
DOMAIN... is a list of domains for the CSR (passed as arguments or input)
|
||||
|
||||
If env variable VERBOSE=1, debug messages are sent to stderr
|
||||
EOT
|
||||
}
|
||||
debug() {
|
||||
if [ "${VERBOSE}" = 1 ]; then
|
||||
>&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}" <<EOF
|
||||
SSLEngine On
|
||||
SSLCertificateFile ${SELF_SIGNED_FILE}
|
||||
SSLCertificateKeyFile ${SSL_KEY_FILE}
|
||||
EOF
|
||||
debug "SSL config added in ${apache_ssl_vhost_path}"
|
||||
else
|
||||
local search="^SSLCertificateFile.*$"
|
||||
local replace="SSLCertificateFile ${SELF_SIGNED_FILE}"
|
||||
|
||||
sed -i "s~${search}~${replace}~" "${apache_ssl_vhost_path}"
|
||||
debug "SSL config updated in ${apache_ssl_vhost_path}"
|
||||
fi
|
||||
}
|
||||
|
||||
sed_selfsigned_cert_path_for_nginx() {
|
||||
local nginx_ssl_vhost_path="$1"
|
||||
|
||||
mkdir -p $(dirname "${nginx_ssl_vhost_path}")
|
||||
if [ ! -f "${nginx_ssl_vhost_path}" ]; then
|
||||
cat > "${nginx_ssl_vhost_path}" <<EOF
|
||||
ssl_certificate ${SELF_SIGNED_FILE};
|
||||
ssl_certificate_key ${SSL_KEY_FILE};
|
||||
EOF
|
||||
debug "SSL config added in ${nginx_ssl_vhost_path}"
|
||||
else
|
||||
local search="^ssl_certificate[^_].*$"
|
||||
local replace="ssl_certificate ${SELF_SIGNED_FILE};"
|
||||
|
||||
sed -i "s~${search}~${replace}~" "${nginx_ssl_vhost_path}"
|
||||
debug "SSL config updated in ${nginx_ssl_vhost_path}"
|
||||
fi
|
||||
}
|
||||
|
||||
openssl_selfsigned() {
|
||||
local csr="$1"
|
||||
local key="$2"
|
||||
local crt="$3"
|
||||
local crt_dir=$(dirname ${crt})
|
||||
|
||||
[ -r "${csr}" ] || error "File ${csr} is not readable"
|
||||
[ -r "${key}" ] || error "File ${key} is not readable"
|
||||
[ -w "${crt_dir}" ] || error "Directory ${crt_dir} is not writable"
|
||||
|
||||
"${OPENSSL_BIN}" x509 -req -sha256 -days 365 -in "${csr}" -signkey "${key}" -out "${crt}" 2> /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" <<EOF
|
||||
mkdir -p -m 0755 "${CSR_DIR}" || error "Unable to mkdir ${CSR_DIR}"
|
||||
|
||||
if [ "${nb}" -eq 1 ]; then
|
||||
cat "${SSL_CONFIG_FILE}" - > "${config_file}" <<EOF
|
||||
CN=$domains
|
||||
EOF
|
||||
openssl req -new -sha256 -key "$SSL_KEY_DIR/${vhost}.key" -config "$config_file" -out "$CSR_DIR/${vhost}.csr"
|
||||
elif [ "$nb" -gt 1 ]; then
|
||||
san=''
|
||||
for domain in $domains
|
||||
do
|
||||
san="$san,DNS:$domain"
|
||||
done
|
||||
san=$(echo "$san"|sed 's/,//')
|
||||
cat /etc/letsencrypt/openssl.cnf - > "$config_file" <<EOF
|
||||
elif [ "${nb}" -gt 1 ]; then
|
||||
for domain in ${domains}; do
|
||||
san="${san},DNS:${domain}"
|
||||
done
|
||||
san=$(echo "${san}" | sed 's/^,//')
|
||||
cat "${SSL_CONFIG_FILE}" - > "${config_file}" <<EOF
|
||||
[SAN]
|
||||
subjectAltName=$san
|
||||
subjectAltName=${san}
|
||||
EOF
|
||||
openssl req -new -sha256 -key "$SSL_KEY_DIR/${vhost}.key" -reqexts SAN -config "$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" <<EOF
|
||||
SSLEngine On
|
||||
SSLCertificateFile $SELF_SIGNED_DIR/${vhost}.pem
|
||||
SSLCertificateKeyFile $SSL_KEY_DIR/${vhost}.key
|
||||
EOF
|
||||
else
|
||||
sed -i "s~^SSLCertificateFile.*$~SSLCertificateFile $SELF_SIGNED_DIR/${vhost}.pem~" "/etc/apache2/ssl/${vhost}.conf"
|
||||
fi
|
||||
}
|
||||
if [ -r "${CSR_FILE}" ]; then
|
||||
chmod 644 "${CSR_FILE}"
|
||||
mkdir -p -m 0755 "${SELF_SIGNED_DIR}"
|
||||
|
||||
mkconf_nginx() {
|
||||
mkdir -p /etc/nginx/ssl
|
||||
if [ ! -f "/etc/nginx/ssl/${vhost}.conf" ]; then
|
||||
cat > "/etc/nginx/ssl/${vhost}.conf" <<EOF
|
||||
ssl_certificate $SELF_SIGNED_DIR/${vhost}.pem;
|
||||
ssl_certificate_key $SSL_KEY_DIR/${vhost}.key;
|
||||
EOF
|
||||
else
|
||||
sed -i "s~^ssl_certificate[^_].*$~ssl_certificate $SELF_SIGNED_DIR/${vhost}.pem;~" "/etc/nginx/ssl/${vhost}.conf"
|
||||
fi
|
||||
openssl_selfsigned "${CSR_FILE}" "${SSL_KEY_FILE}" "${SELF_SIGNED_FILE}"
|
||||
|
||||
[ -r "${SELF_SIGNED_FILE}" ] && chmod 644 "${SELF_SIGNED_FILE}"
|
||||
debug "Self-signed certificate stored at ${SELF_SIGNED_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "You need to provide one argument !" >&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}
|
||||
|
|
153
evoacme/files/vhost-domains.sh
Executable file
153
evoacme/files/vhost-domains.sh
Executable file
|
@ -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 <vlaborie@evolix.fr>
|
||||
# Licence: AGPLv3
|
||||
#
|
||||
|
||||
set -u
|
||||
|
||||
usage() {
|
||||
cat <<EOT
|
||||
Usage: ${PROGNAME} VHOST
|
||||
VHOST must correspond to an Apache or Nginx enabled VHost
|
||||
If VHOST ends with ".conf" it is stripped,
|
||||
then files are seached at those paths:
|
||||
- /etc/apache2/sites-enables/VHOST.conf
|
||||
- /etc/nginx/sites-enabled/VHOST.conf
|
||||
- /etc/nginx/sites-enabled/VHOST
|
||||
|
||||
If env variable VERBOSE=1, debug messages are sent to stderr
|
||||
EOT
|
||||
}
|
||||
|
||||
debug() {
|
||||
if [ "${VERBOSE}" = 1 ]; then
|
||||
>&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
|
|
@ -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 }}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }}"
|
||||
|
|
14
evoacme/tasks/evoacme_hook.yml
Normal file
14
evoacme/tasks/evoacme_hook.yml
Normal file
|
@ -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 == ""
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
9
evolinux-base/files/alert5.service
Normal file
9
evolinux-base/files/alert5.service
Normal file
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Evolix alert5 script
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/share/scripts/alert5.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
31
evolinux-base/files/hwraid.le-vert.net.gpg.key
Normal file
31
evolinux-base/files/hwraid.le-vert.net.gpg.key
Normal file
|
@ -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-----
|
|
@ -12,6 +12,7 @@ galaxy_info:
|
|||
- name: Debian
|
||||
versions:
|
||||
- jessie
|
||||
- stretch
|
||||
|
||||
dependencies: []
|
||||
# List your role dependencies here, one per line.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
- apg
|
||||
- conntrack
|
||||
- logrotate
|
||||
- bash-completion
|
||||
- ssl-cert
|
||||
- ca-certificates
|
||||
when: evolinux_packages_system
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
|
||||
- name: packages are installed
|
||||
- name: Postfix packages are installed
|
||||
apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
7
evolinux-base/templates/system/alert5.sh.j2
Normal file
7
evolinux-base/templates/system/alert5.sh.j2
Normal file
|
@ -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
|
|
@ -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'
|
||||
|
|
@ -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'
|
||||
```
|
4
evolinux-users/defaults/main.yml
Normal file
4
evolinux-users/defaults/main.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
evolinux_users: {}
|
||||
evolinux_sudo_group: "evolinux-sudo"
|
||||
evolinux_root_disable_ssh: True
|
|
@ -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
|
||||
|
|
@ -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"
|
20
evolinux-users/tasks/main.yml
Normal file
20
evolinux-users/tasks/main.yml
Normal file
|
@ -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
|
16
evolinux-users/tasks/profile.yml
Normal file
16
evolinux-users/tasks/profile.yml
Normal file
|
@ -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
|
17
evolinux-users/tasks/root_disable_ssh.yml
Normal file
17
evolinux-users/tasks/root_disable_ssh.yml
Normal file
|
@ -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
|
|
@ -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
|
18
evolinux-users/tasks/sudo_jessie.yml
Normal file
18
evolinux-users/tasks/sudo_jessie.yml
Normal file
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue