Bläddra i källkod

Add support for Let's Encrypt

Emmanuel Bouthenot 7 år sedan
förälder
incheckning
50eabeec17

+ 1 - 0
roles/common/defaults/main.yml

@@ -78,6 +78,7 @@ dotfiles_dest: '/srv/hosting-tools/shell'
 dotfiles_lcsshvars: 0
 
 ssl_certs: Null
+ssl_certs_auto: Null
 
 dkim_domains: Null
 with_opendkim: False

+ 1 - 0
roles/common/handlers/main.yml

@@ -4,4 +4,5 @@
 - include: smtp.yml
 - include: dkim.yml
 - include: ssh.yml
+- include: ssl.yml
 - include: smartd.yml

+ 3 - 0
roles/common/handlers/ssl.yml

@@ -0,0 +1,3 @@
+- name: 'Generate Lets Encrypt SSL certificates'
+  shell: letsencrypt.sh --cron >/dev/null
+  ignore_errors: True

+ 40 - 0
roles/common/tasks/ssl.yml

@@ -58,3 +58,43 @@
   shell: sed '/^\s*$/d' '/etc/ssl/local/certs/{{ item.item }}/privkey.pem' '/etc/ssl/local/certs/{{ item.item }}/cert.pem' '/etc/ssl/local/certs/{{ item.item }}/chain.pem' > '/etc/ssl/local/certs/{{ item.item }}/bundle.pem'
   with_items: '{{ ssl_bundle_stats.results }}'
   when: not item.stat.exists or ssl_key_result|changed or ssl_cert_result|changed or ssl_chain_result|changed
+
+- name: 'Install Lets Encrypt client'
+  apt:
+    pkg: 'dehydrated'
+    state: 'installed'
+  when: ssl_certs_auto
+
+- name: 'Install Lets Encrypt domains configuration'
+  template:
+    src: 'ssl/letsencrypt_domains.j2'
+    dest: '/etc/dehydrated/domains.txt'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  when: ssl_certs_auto
+
+- name: 'List Lets Encrypt SSL installed certificates'
+  shell: find /var/lib/dehydrated/certs -iname privkey.pem | cut -d / -f6
+  register: ssl_certs_auto_installed
+  changed_when: False
+  ignore_errors: True
+  when: ssl_certs_auto
+
+- name: 'List Lets Encrypt SSL certificates to be generated'
+  shell: egrep -v '^#' /etc/dehydrated/domains.txt | while read c ; do test -f "/var/lib/dehydrated/certs/${c}/privkey.pem" || echo "${c}" ; done
+  register: ssl_certs_auto_missing
+  ignore_errors: True
+  changed_when: ssl_certs_auto_missing.stdout_lines != []
+  notify:
+    - 'Generate Lets Encrypt SSL certificates'
+  when: ssl_certs_auto
+
+- name: 'Install Lets Encrypt cron job'
+  template:
+    src: 'cron/letsencrypt.j2'
+    dest: '/etc/cron.d/letsencrypt-local'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  when: ssl_certs_auto

+ 13 - 0
roles/common/templates/cron/letsencrypt.j2

@@ -0,0 +1,13 @@
+{% if ansible_prolog -%}
+{% from 'templates/ansible/prolog.j2' import prolog with context %}
+{{ prolog() }}
+{% endif -%}
+# /etc/cron.d/letsencrypt-local:
+# Sign/renew non-existant/changed/expiring certificates generated with Let's
+# Encrypt
+
+SHELL=/bin/sh
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+MAILTO=root
+
+@daily      root    dehydrated --cron 2>&1 1>/dev/null | grep -v 'WARNING.*Extra configuration directory.*exists, but no configuration found'

+ 9 - 0
roles/common/templates/ssl/letsencrypt_domains.j2

@@ -0,0 +1,9 @@
+{% if ansible_prolog -%}
+{% from 'templates/ansible/prolog.j2' import prolog with context %}
+{{ prolog() }}
+{% endif -%}
+{% if ssl_certs_auto is defined %}
+{% for d in ssl_certs_auto %}
+{{ d }}
+{% endfor %}
+{% endif %}

+ 4 - 2
roles/webserver/defaults/main.yml

@@ -31,7 +31,8 @@ with_php_mysql_legacy: False
 
 phpsyscheck_vhostname: 'sys.localhost'
 phpsyscheck_vhostip: Null
-phpsyscheck_vhostport: 80
+phpsyscheck_vhostport: Null
+phpsyscheck_ssl: False
 
 php_config:
   date.timezone: 'Europe/Paris'
@@ -51,7 +52,8 @@ with_php_apc: False
 with_phpmyadmin: False
 phpmyadmin_vhostname: 'pma.localhost'
 phpmyadmin_vhostip: Null
-phpmyadmin_vhostport: 80
+phpmyadmin_vhostport: Null
+phpmyadmin_ssl: False
 http_auth_phpmyadmin: False
 
 with_phppgadmin: False

+ 32 - 0
roles/webserver/tasks/apache2.yml

@@ -23,6 +23,18 @@
     - 'Reload apache2'
   when: ssl_certs
 
+- name: 'Install SSL vhost configuration for Apache (Lets Encrypt certificates)'
+  template:
+    src: 'apache2/vhost_ssl_auto.j2'
+    dest: '/etc/apache2/vhost_ssl_auto-{{ item }}.conf'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  with_items: '{{ ssl_certs_auto }}'
+  notify:
+    - 'Reload apache2'
+  when: ssl_certs_auto
+
 - name: 'Install Apache2 basic security configuration (Debian < 8)'
   template:
     src: 'apache2/conf.d/security.j2'
@@ -45,6 +57,26 @@
     - 'Reload apache2'
   when: ansible_lsb.major_release|int >= 8
 
+- name: 'Install Lets Encrypt configuration for Apache2 (conf-available)'
+  template:
+    src: 'apache2/letsencrypt.j2'
+    dest: '/etc/apache2/conf-available/letsencrypt.conf'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  notify:
+    - 'Reload apache2'
+  when: ssl_certs_auto
+
+- name: 'Install Lets Encrypt configuration for Apache2 (conf-enabled)'
+  file:
+    src: '/etc/apache2/conf-available/letsencrypt.conf'
+    path: '/etc/apache2/conf-enabled/letsencrypt.conf'
+    state: 'link'
+  notify:
+    - 'Reload apache2'
+  when: ssl_certs_auto
+
 - name: 'Create basic authentication file for admin (Apache2)'
   template:
     src: 'apache2/auth_admin.j2'

+ 23 - 0
roles/webserver/tasks/nginx.yml

@@ -81,6 +81,29 @@
     - 'Reload nginx'
   when: ssl_certs
 
+- name: 'Install SSL vhost configuration for Nginx (Lets Encrypt certificates)'
+  template:
+    src: 'nginx/vhost_ssl_auto.j2'
+    dest: '/etc/nginx/vhost_ssl_auto-{{ item }}'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  with_items: '{{ ssl_certs_auto }}'
+  notify:
+    - 'Reload nginx'
+  when: ssl_certs_auto
+
+- name: 'Install Let Encrypt configuration for Nginx'
+  template:
+    src: 'nginx/letsencrypt.j2'
+    dest: '/etc/nginx/letsencrypt'
+    owner: 'root'
+    group: 'root'
+    mode: '0644'
+  notify:
+    - 'Reload nginx'
+  when: ssl_certs_auto
+
 - name: 'Create basic authentication file for admin (Nginx)'
   template:
     src: 'nginx/auth_admin.j2'

+ 24 - 0
roles/webserver/templates/apache2/letsencrypt.j2

@@ -0,0 +1,24 @@
+{% if ansible_prolog -%}
+{% from 'templates/ansible/prolog.j2' import prolog with context %}
+{{ prolog() }}
+{% endif -%}
+<IfModule proxy_module>
+    # Do not proxy ACME challenge responses
+    ProxyPass /.well-known/acme-challenge/ !
+</IfModule>
+<IfModule !alias_module>
+    # Load the alias module, if not loaded already
+    Include /etc/apache2/mods-available/alias.load
+    Include /etc/apache2/mods-available/alias.conf
+</IfModule>
+<IfModule alias_module>
+    # Serve ACME challenge responses
+    Alias /.well-known/acme-challenge/ /var/lib/dehydrated/acme-challenges/
+</IfModule>
+<Directory /var/lib/dehydrated/acme-challenges/>
+    Options FollowSymlinks
+    Options -Indexes
+    AllowOverride None
+    Require all granted
+    Satisfy Any
+</Directory>

+ 4 - 0
roles/webserver/templates/apache2/vhost_ssl_auto.j2

@@ -0,0 +1,4 @@
+SSLEngine On
+SSLCertificateFile /var/lib/dehydrated/certs/{{ item }}/cert.pem
+SSLCertificateKeyFile /var/lib/dehydrated/certs/{{ item }}/privkey.pem
+SSLCertificateChainFile /var/lib/dehydrated/certs/{{ item }}/chain.pem

+ 10 - 0
roles/webserver/templates/nginx/letsencrypt.j2

@@ -0,0 +1,10 @@
+{% if ansible_prolog -%}
+{% from 'templates/ansible/prolog.j2' import prolog with context %}
+{{ prolog() }}
+{% endif -%}
+location /.well-known/acme-challenge/ {
+    auth_basic off;
+    default_type text/plain;
+    alias /var/lib/dehydrated/acme-challenges/;
+    try_files $uri =404;
+}

+ 3 - 0
roles/webserver/templates/nginx/vhost_ssl_auto.j2

@@ -0,0 +1,3 @@
+ssl_certificate /var/lib/dehydrated/certs/{{ item }}/fullchain.pem;
+ssl_certificate_key /var/lib/dehydrated/certs/{{ item }}/privkey.pem;
+ssl_trusted_certificate /var/lib/dehydrated/certs/{{ item }}/chain.pem;