From b485b0b49cec886c824bc06ee9ea9200e24d444d Mon Sep 17 00:00:00 2001 From: Victor LABORIE Date: Wed, 14 Dec 2016 15:49:34 +0100 Subject: [PATCH] Evoacme: merge role from evoacme private repo --- evoacme/README.md | 51 ++++++++++++++++++++ evoacme/defaults/main.yml | 15 ++++++ evoacme/files/certbot.cron | 6 +++ evoacme/files/evoacme.sh | 67 ++++++++++++++++++++++++++ evoacme/files/make-csr.sh | 67 ++++++++++++++++++++++++++ evoacme/files/sudoers | 1 + evoacme/handlers/main.yml | 11 +++++ evoacme/tasks/acme.yml | 45 +++++++++++++++++ evoacme/tasks/apache.yml | 17 +++++++ evoacme/tasks/certbot.yml | 80 +++++++++++++++++++++++++++++++ evoacme/tasks/conf.yml | 33 +++++++++++++ evoacme/tasks/dhparam.yml | 3 ++ evoacme/tasks/main.yml | 12 +++++ evoacme/tasks/nginx.yml | 7 +++ evoacme/tasks/scripts.yml | 24 ++++++++++ evoacme/tasks/webserver.yml | 8 ++++ evoacme/templates/apache.conf.j2 | 7 +++ evoacme/templates/evoacme.conf.j2 | 8 ++++ evoacme/templates/nginx.conf.j2 | 4 ++ 19 files changed, 466 insertions(+) create mode 100644 evoacme/README.md create mode 100644 evoacme/defaults/main.yml create mode 100755 evoacme/files/certbot.cron create mode 100755 evoacme/files/evoacme.sh create mode 100755 evoacme/files/make-csr.sh create mode 100644 evoacme/files/sudoers create mode 100644 evoacme/handlers/main.yml create mode 100644 evoacme/tasks/acme.yml create mode 100644 evoacme/tasks/apache.yml create mode 100644 evoacme/tasks/certbot.yml create mode 100644 evoacme/tasks/conf.yml create mode 100644 evoacme/tasks/dhparam.yml create mode 100644 evoacme/tasks/main.yml create mode 100644 evoacme/tasks/nginx.yml create mode 100644 evoacme/tasks/scripts.yml create mode 100644 evoacme/tasks/webserver.yml create mode 100644 evoacme/templates/apache.conf.j2 create mode 100644 evoacme/templates/evoacme.conf.j2 create mode 100644 evoacme/templates/nginx.conf.j2 diff --git a/evoacme/README.md b/evoacme/README.md new file mode 100644 index 00000000..871b6e70 --- /dev/null +++ b/evoacme/README.md @@ -0,0 +1,51 @@ +# Evoacme 1.3 + +EvoAcme is an [Ansible](https://www.ansible.com/) role and a [Certbot](https://certbot.eff.org) wrapper for generate [Let's Encrypt](https://letsencrypt.org/) certificates. + +It is a project hosted at [Evolix's forge](https://forge.evolix.org/projects/ansible-roles/repository/revisions/master/show/evoacme) + +# How to install + +1 - Create a playbook with evoacme role + +``` +--- + - hosts: hostname + become: yes + roles: + - role: evoacme +``` + +2 - Install evoacme prerequisite with ansible + +``` +ansible-playbook playbook.yml -Kl hostname +``` + +3 - Include letsencrypt.conf in your webserver + +For Apache, you just need to ensure that you don't overwrite "/.well-known/acme-challenge" Alias with a Redirect or Rewrite directive. + +For Nginx, you must include letsencrypt.conf in all wanted vhost : +``` +include /etc/nginx/letsencrypt.conf; +nginx -t +service nginx reload +``` + +4 - Create a CSR for a vhost with make-csr + +``` +# vhostname is vhostfile without .conf ext +make-csr vhostname +``` + +8 - Generate the certificate with evoacme + +``` +evoacme vhostname +``` + +# License + +Evoacme is open source software licensed under the AGPLv3 License. diff --git a/evoacme/defaults/main.yml b/evoacme/defaults/main.yml new file mode 100644 index 00000000..4d7fc9df --- /dev/null +++ b/evoacme/defaults/main.yml @@ -0,0 +1,15 @@ +--- +ssl_key_dir: /etc/ssl/private +ssl_key_size: 2048 +dhparam_size: 2048 +acme_dir: /var/lib/letsencrypt +csr_dir: /etc/ssl/requests +crt_dir: /etc/letsencrypt +log_dir: /var/log/evoacme +ssl_minday: 15 +ssl_ct: 'FR' +ssl_state: 'France' +ssl_loc: 'Marseille' +ssl_org: 'Evolix' +ssl_ou: 'Security' +ssl_email: 'security@evolix.net' diff --git a/evoacme/files/certbot.cron b/evoacme/files/certbot.cron new file mode 100755 index 00000000..25722e73 --- /dev/null +++ b/evoacme/files/certbot.cron @@ -0,0 +1,6 @@ +#!/bin/bash + +ls /etc/letsencrypt/*.crt|sed 's/.crt//'|while read vhost; +do + evoacme $(basename $vhost)>/dev/null +done diff --git a/evoacme/files/evoacme.sh b/evoacme/files/evoacme.sh new file mode 100755 index 00000000..eb9f5185 --- /dev/null +++ b/evoacme/files/evoacme.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +source /etc/default/evoacme + +vhost=$1 + +SSL_EMAIL=$(grep emailAddress /etc/letsencrypt/openssl.cnf|cut -d'=' -f2|xargs) +if [ -n "$SSL_EMAIL" ]; then + emailopt="--email $SSL_EMAIL" +else + emailopt="--register-unsafely-without-email" +fi + +if [ -f $CRT_DIR/${vhost}.crt ]; then + renew=true + crt_end_date=`openssl x509 -noout -enddate -in $CRT_DIR/${vhost}.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) )) + if [ $date_diff -ge $SSL_MINDAY ]; then + exit 0 + fi +fi + +rm -f $CRT_DIR/${vhost}.crt $CRT_DIR/${vhost}-fullchain.pem $CRT_DIR/${vhost}-chain.pem + +sudo -u acme certbot certonly --quiet --webroot --csr $CSR_DIR/${vhost}.csr --webroot-path $ACME_DIR -n --agree-tos --cert-path=$CRT_DIR/${vhost}.crt --fullchain-path=$CRT_DIR/${vhost}-fullchain.pem --chain-path=$CRT_DIR/${vhost}-chain.pem $emailopt --logs-dir $LOG_DIR 2> >(grep -v certbot.crypto_util) + +if [ $? != 0 ]; then + exit 1 +fi + +which apache2ctl>/dev/null +if [ $? == 0 ]; then + apache2ctl -t 2>/dev/null + if [ $? == 0 ]; then + service apache2 reload + fi +fi +which nginx>/dev/null +if [ $? == 0 ]; then + nginx -t 2>/dev/null + if [ $? == 0 ]; then + service nginx reload + fi +fi + +if [ -z "$renew" ]; then + +cat < $CSR_DIR/${vhost}.csr +fi + +if [ -f $CSR_DIR/${vhost}.csr ]; then + chown root: $CSR_DIR/${vhost}.csr + chmod 644 $CSR_DIR/${vhost}.csr + if [ ! -f $CRT_DIR/${vhost}-fullchain.pem ]; then + echo "Generate autosigned cert" + openssl x509 -req -sha256 -days 365 -in $CSR_DIR/${vhost}.csr -signkey $SSL_KEY_DIR/${vhost}.key -out $CRT_DIR/${vhost}-fullchain.pem + fi +fi diff --git a/evoacme/files/sudoers b/evoacme/files/sudoers new file mode 100644 index 00000000..4a43bce3 --- /dev/null +++ b/evoacme/files/sudoers @@ -0,0 +1 @@ +acme ALL=(ALL:ALL) NOPASSWD: /opt/certbot/certbot-auto diff --git a/evoacme/handlers/main.yml b/evoacme/handlers/main.yml new file mode 100644 index 00000000..e5538908 --- /dev/null +++ b/evoacme/handlers/main.yml @@ -0,0 +1,11 @@ +- name: newaliases + shell: newaliases + +- name: Test Apache conf + shell: apache2ctl -t + notify: "Reload Apache conf" + +- name: Reload Apache conf + service: + name=apache2 + state=reloaded diff --git a/evoacme/tasks/acme.yml b/evoacme/tasks/acme.yml new file mode 100644 index 00000000..80cbb2c0 --- /dev/null +++ b/evoacme/tasks/acme.yml @@ -0,0 +1,45 @@ +--- +- name: Create acme group + group: + name: acme + state: present + +- name: Create acme user + user: + name: acme + group: acme + state: present + createhome: no + home: "{{ crt_dir }}" + shell: /bin/false + +- name: Fix crt dir's right + file: + path: "{{ crt_dir }}" + mode: 0755 + owner: acme + group: acme + state: directory + +- name: Fix log dir's right + file: + path: "{{ log_dir }}" + mode: 0755 + owner: acme + group: acme + state: directory + +- name: Fix challenge dir's right + file: + path: "{{ acme_dir }}" + mode: 0755 + owner: acme + group: acme + state: directory + +- name: Set acme aliases + lineinfile: + state: present + dest: /etc/aliases + line: 'acme: root' + notify: "newaliases" diff --git a/evoacme/tasks/apache.yml b/evoacme/tasks/apache.yml new file mode 100644 index 00000000..d0c3e478 --- /dev/null +++ b/evoacme/tasks/apache.yml @@ -0,0 +1,17 @@ +- name: Copy acme challenge conf + template: + src: templates/apache.conf.j2 + dest: /etc/apache2/conf-available/letsencrypt.conf + owner: root + group: root + mode: 0644 + notify: "Test Apache conf" + +- name: Enable acme challenge conf + file: + src: /etc/apache2/conf-available/letsencrypt.conf + dest: /etc/apache2/conf-enabled/letsencrypt.conf + state: link + owner: root + group: root + notify: "Test Apache conf" diff --git a/evoacme/tasks/certbot.yml b/evoacme/tasks/certbot.yml new file mode 100644 index 00000000..4ff6072c --- /dev/null +++ b/evoacme/tasks/certbot.yml @@ -0,0 +1,80 @@ +--- +- name: Set certbot release to Debian stable + set_fact: release="stable" + when: + - ansible_distribution is defined + - ansible_distribution == "Debian" + - ansible_distribution_major_version is defined + - ansible_distribution_major_version|int > 8 + +- name: Set certbot relase to jessie-backports + set_fact: release="jessie-backports" + when: + - ansible_distribution is defined + - ansible_distribution == "Debian" + - ansible_distribution_major_version is defined + - ansible_distribution_major_version == "8" + +- block: + - name: Add backports repository + lineinfile: + dest: /etc/apt/sources.list + line: 'deb http://mirror.evolix.org/debian jessie-backports main' + state: present + when: release == "jessie-backports" + + - name: Install certbot with apt + apt: + name: certbot + state: latest + default_release: "{{release}}" + update_cache: yes + + - name: Mount /usr in rw + command: mount -o remount,rw /usr warn=no + changed_when: False + + - name: Remove certbot symlink for apt install + file: + path: /usr/local/bin/certbot + state: absent + when: release is defined + +- block: + - name: Install certbot from source + git: + repo: https://github.com/certbot/certbot.git + dest: /opt/certbot + update: yes + + - name: Fix certbot right for source install + file: + path: /opt/certbot + recurse: yes + state: directory + mode: "g+rX,o+rX" + + - name: Install certbot symlink for source install + copy: + dest: /usr/local/bin/certbot + content: '#!/bin/sh\nsudo /opt/certbot/certbot-auto $@' + mode: 0755 + + - name: Add sudo right for source install + copy: + src: files/sudoers + dest: /etc/sudoers.d/certbot + mode: 0440 + validate: '/usr/sbin/visudo -cf %s' + when: release is undefined + +- name: Remove certbot dpkg cron + file: + path: /etc/cron.d/certbot + state: absent + +- name: Install certbot custom cron + copy: + src: certbot.cron + dest: /etc/cron.daily/certbot + mode: 0755 diff --git a/evoacme/tasks/conf.yml b/evoacme/tasks/conf.yml new file mode 100644 index 00000000..1b137302 --- /dev/null +++ b/evoacme/tasks/conf.yml @@ -0,0 +1,33 @@ +--- +- ini_file: + dest: /etc/letsencrypt/openssl.cnf + section: 'req' + option: "{{ item.name }}" + value: "{{ item.var }}" + with_items: + - { name: 'default_bits', var: "{{ ssl_key_size }}" } + - { name: 'encrypt_key', var: 'yes' } + - { name: 'distinguished_name', var: 'req_dn' } + - { name: 'prompt', var: 'no' } + +- name: Update openssl conf + ini_file: + dest: "{{ crt_dir }}/openssl.cnf" + section: 'req_dn' + option: "{{ item.name }}" + value: "{{ item.var }}" + with_items: + - { name: 'C', var: "{{ ssl_ct }}" } + - { name: 'ST', var: "{{ ssl_state }}" } + - { name: 'L', var: "{{ ssl_loc }}" } + - { name: 'O', var: "{{ ssl_org }}" } + - { name: 'OU', var: "{{ ssl_ou }}" } + - { name: 'emailAddress', var: "{{ ssl_email }}" } + +- name: Copy new evoacme conf + template: + src: templates/evoacme.conf.j2 + dest: /etc/default/evoacme + owner: root + group: root + mode: 0644 diff --git a/evoacme/tasks/dhparam.yml b/evoacme/tasks/dhparam.yml new file mode 100644 index 00000000..599efe23 --- /dev/null +++ b/evoacme/tasks/dhparam.yml @@ -0,0 +1,3 @@ +- name: Generate DH paramaters + shell: openssl dhparam -rand - {{dhparam_size}} -out /etc/ssl/dhparam.pem + creates=/etc/ssl/dhparam.pem diff --git a/evoacme/tasks/main.yml b/evoacme/tasks/main.yml new file mode 100644 index 00000000..25fcdebf --- /dev/null +++ b/evoacme/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- include: tasks/certbot.yml +- include: tasks/acme.yml +- include: tasks/conf.yml +- include: tasks/scripts.yml +- include: tasks/webserver.yml +- include: tasks/apache.yml + when: sta.stat.isreg is defined and sta.stat.isreg == True +- include: tasks/nginx.yml + when: stn.stat.isreg is defined and stn.stat.isreg == True +- include: tasks/dhparam.yml + when: stn.stat.isreg is defined and stn.stat.isreg == True diff --git a/evoacme/tasks/nginx.yml b/evoacme/tasks/nginx.yml new file mode 100644 index 00000000..f8b625ff --- /dev/null +++ b/evoacme/tasks/nginx.yml @@ -0,0 +1,7 @@ +- name: Copy acme challenge conf + template: + src: templates/nginx.conf.j2 + dest: /etc/nginx/letsencrypt.conf + owner: root + group: root + mode: 0644 diff --git a/evoacme/tasks/scripts.yml b/evoacme/tasks/scripts.yml new file mode 100644 index 00000000..92bfba63 --- /dev/null +++ b/evoacme/tasks/scripts.yml @@ -0,0 +1,24 @@ +--- +- name: Create CSR dir + file: + path: "{{ csr_dir }}" + state: directory + owner: root + group: root + mode: 0755 + +- name: Copy make-csr.sh script + copy: + src: files/make-csr.sh + dest: /usr/local/bin/make-csr + owner: root + group: root + mode: 0755 + +- name: Copy evoacme script + copy: + src: files/evoacme.sh + dest: /usr/local/bin/evoacme + owner: root + group: root + mode: 0755 diff --git a/evoacme/tasks/webserver.yml b/evoacme/tasks/webserver.yml new file mode 100644 index 00000000..e628b674 --- /dev/null +++ b/evoacme/tasks/webserver.yml @@ -0,0 +1,8 @@ +--- +- name: Determine Nginx presence + stat: path=/etc/nginx/nginx.conf + register: stn + +- name: Determine Apache presence + stat: path=/etc/apache2/apache2.conf + register: sta diff --git a/evoacme/templates/apache.conf.j2 b/evoacme/templates/apache.conf.j2 new file mode 100644 index 00000000..bad9f9c9 --- /dev/null +++ b/evoacme/templates/apache.conf.j2 @@ -0,0 +1,7 @@ +SetEnvIf Request_URI "/.well-known/acme-challenge/*" no-jk +Alias /.well-known/acme-challenge {{ acme_dir }}/.well-known/acme-challenge + + Options -Indexes + Allow from all + Require all granted + diff --git a/evoacme/templates/evoacme.conf.j2 b/evoacme/templates/evoacme.conf.j2 new file mode 100644 index 00000000..b397159f --- /dev/null +++ b/evoacme/templates/evoacme.conf.j2 @@ -0,0 +1,8 @@ +### File generated by Ansible ### + +SSL_KEY_DIR={{ssl_key_dir}} +ACME_DIR={{acme_dir}} +CSR_DIR={{csr_dir}} +CRT_DIR={{crt_dir}} +LOG_DIR={{log_dir}} +SSL_MINDAY={{ssl_minday}} diff --git a/evoacme/templates/nginx.conf.j2 b/evoacme/templates/nginx.conf.j2 new file mode 100644 index 00000000..3ec7e3f3 --- /dev/null +++ b/evoacme/templates/nginx.conf.j2 @@ -0,0 +1,4 @@ +location /.well-known/acme-challenge { + alias {{ acme_dir }}/.well-known/acme-challenge; + try_files $uri =404; +}