diff --git a/README.md b/README.md index db6a0988..731d28eb 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Set up (the latest version of) [HAProxy](http://www.haproxy.org/) in Ubuntu syst * `haproxy_default_raw_options`: [default: `[]`]: Additional arbitrary lines to insert in the section * `haproxy_ssl_map`: [default: `[]`]: SSL declarations +* `haproxy_ssl_map.{n}.state`: [default: `present`]: Whether to ensure the file is present or absent * `haproxy_ssl_map.{n}.src`: The local path of the file to copy, can be absolute or relative (e.g. `../../../files/haproxy/etc/haproxy/ssl/star-example-com.pem`) * `haproxy_ssl_map.{n}.dest`: The remote path of the file to copy (e.g. `/etc/haproxy/ssl/star-example-com.pem`) * `haproxy_ssl_map.{n}.owner`: The name of the user that should own the file (optional, default `root`) @@ -422,6 +423,22 @@ Set up (the latest version of) [HAProxy](http://www.haproxy.org/) in Ubuntu syst * `haproxy_acl_files.{n}.dest`: [required]: The remote path of the file (e.g. `/etc/haproxy/acl/api.map`) * `haproxy_acl_files.{n}.content`: [default: `[]`]: The content (lines) of the file (e.g. `['v1.0 be_alpha', 'v1.1 be_bravo']`) +* `haproxy_letsencrypt_ssl_deploy_template`: [default: `usr/local/bin/haproxy-letsencrypt-ssl-deploy.j2`]: Template to deploy SSL certificates after creation and renewal by Letsencrypt +* `haproxy_letsencrypt_ssl_first_cert`: [default: `inventory_hostname`]: Name of the certificate that should be the first +* `haproxy_letsencrypt_ssl_src_path`: [default: `/etc/letsencrypt/live`]: Path to the directory with the certificates (in directories) +* `haproxy_letsencrypt_ssl_fullchain_name`: [default: `fullchain.pem`]: Filename of the fullchain certificate +* `haproxy_letsencrypt_ssl_chain_name`: [default: `chain.pem`]: Filename of the chain certificate +* `haproxy_letsencrypt_ssl_privkey_name`: [default: `privkey.pem`]: Filename of the private key +* `haproxy_letsencrypt_ssl_cert_name`: [default: `cert.pem`]: Filename of the certificate +* `haproxy_letsencrypt_ocsp_deploy_template`: [default: `usr/local/bin/haproxy-letsencrypt-ocsp-deploy.j2`]: Template to deploy OCSP certificates after creation, renewal (by Letsencrypt) and daily +* `haproxy_letsencrypt_ocsp_deploy_job`: [optional]: OCSP deploy job (scheduled by `cron.d`) +* `haproxy_letsencrypt_ocsp_deploy_job.state`: [default: `absent`]: Whether to ensure the job is present or absent +* `haproxy_letsencrypt_ocsp_deploy_job.day`: [default: `*`]: Day of the month the job should run (`1-31`, `*`, `*/2`) +* `haproxy_letsencrypt_ocsp_deploy_job.hour`: [default: `0`]: Hour when the job should run (e.g. `0-23`, `*`, `*/2`) +* `haproxy_letsencrypt_ocsp_deploy_job.minute`: [default: `*`]: Minute when the job should run (e.g. `0-59`, `*`, `*/2`) +* `haproxy_letsencrypt_ocsp_deploy_job.month`: [default: `*`]: Month of the year the job should run (e.g `1-12`, `*`, `*/2`) +* `haproxy_letsencrypt_ocsp_deploy_job.weekday`: [default: `*`]: Day of the week that the job should run (e.g. `0-6` for Sunday-Saturday, `*`) + ## Dependencies None diff --git a/defaults/main.yml b/defaults/main.yml index 7e840663..ee5cf0da 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -87,3 +87,14 @@ haproxy_resolvers: [] # ACL files haproxy_acl_files: [] + +# Letsencrypt (SSL/OCSP deploy) +haproxy_letsencrypt_ssl_deploy_template: usr/local/bin/haproxy-letsencrypt-ssl-deploy.j2 +haproxy_letsencrypt_ssl_first_cert: "{{ inventory_hostname }}" +haproxy_letsencrypt_ssl_src_path: /etc/letsencrypt/live +haproxy_letsencrypt_ssl_fullchain_name: fullchain.pem +haproxy_letsencrypt_ssl_chain_name: chain.pem +haproxy_letsencrypt_ssl_privkey_name: privkey.pem +haproxy_letsencrypt_ssl_cert_name: cert.pem +haproxy_letsencrypt_ocsp_deploy_template: usr/local/bin/haproxy-letsencrypt-ocsp-deploy.j2 +haproxy_letsencrypt_ocsp_deploy_job: {} diff --git a/tasks/certificates.yml b/tasks/certificates.yml index 947d9948..10fc7d5f 100644 --- a/tasks/certificates.yml +++ b/tasks/certificates.yml @@ -8,6 +8,7 @@ group: "{{ item.group | default('root') }}" mode: 0750 with_items: "{{ haproxy_ssl_map }}" + when: item.state is undefined or item.state == 'present' tags: - haproxy-certificates-create-directories @@ -19,6 +20,17 @@ group: "{{ item.group | default('root') }}" mode: "{{ item.mode | default('0640') }}" with_items: "{{ haproxy_ssl_map }}" + when: item.state is undefined or item.state == 'present' notify: restart haproxy tags: - haproxy-certificates-copy-files + +- name: certificates | remove files + file: + path: "{{ item.dest }}" + state: absent + with_items: "{{ haproxy_ssl_map }}" + when: item.state is defined and item.state == 'absent' + notify: restart haproxy + tags: + - haproxy-certificates-remove-files diff --git a/tasks/letsencrypt.yml b/tasks/letsencrypt.yml new file mode 100644 index 00000000..b2fda3c6 --- /dev/null +++ b/tasks/letsencrypt.yml @@ -0,0 +1,36 @@ +# tasks file for haproxy +--- +- name: letsencrypt | copy SSL deploy script + template: + src: "{{ haproxy_letsencrypt_ssl_deploy_template }}" + dest: "{{ haproxy_letsencrypt_ssl_deploy }}" + owner: root + group: root + mode: 0755 + tags: + - haproxy-letsencrypt-ssl-deploy + +- name: letsencrypt | copy OCSP deploy script + template: + src: "{{ haproxy_letsencrypt_ocsp_deploy_template }}" + dest: "{{ haproxy_letsencrypt_ocsp_deploy }}" + owner: root + group: root + mode: 0755 + tags: + - haproxy-letsencrypt-ocsp-deploy + +- name: letsencrypt | configure (cron) job for OCSP deploy + cron: + name: haproxy-letsencrypt-ocsp-deploy + job: "{{ haproxy_letsencrypt_ocsp_deploy }}" + state: "{{ haproxy_letsencrypt_ocsp_deploy_job.state | default('absent') }}" + day: "{{ haproxy_letsencrypt_ocsp_deploy_job.day | default('*') }}" + hour: "{{ haproxy_letsencrypt_ocsp_deploy_job.hour | default(0) }}" + minute: "{{ haproxy_letsencrypt_ocsp_deploy_job.minute | default(0) }}" + month: "{{ haproxy_letsencrypt_ocsp_deploy_job.month | default('*') }}" + weekday: "{{ haproxy_letsencrypt_ocsp_deploy_job.weekday | default('*') }}" + cron_file: haproxy-letsencrypt-ocsp-deploy + user: root + tags: + - haproxy-letsencrypt-cron-ocsp-deploy diff --git a/tasks/main.yml b/tasks/main.yml index 8b2cba3c..88668267 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -33,6 +33,12 @@ - haproxy - haproxy-configuration +- import_tasks: letsencrypt.yml + tags: + - configuration + - haproxy + - haproxy-letsencrypt + - name: start and enable service service: name: haproxy diff --git a/templates/usr/local/bin/haproxy-letsencrypt-ocsp-deploy.j2 b/templates/usr/local/bin/haproxy-letsencrypt-ocsp-deploy.j2 new file mode 100644 index 00000000..98730664 --- /dev/null +++ b/templates/usr/local/bin/haproxy-letsencrypt-ocsp-deploy.j2 @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# +# {{ ansible_managed }} +# +# set -x; +set -e; +set -o pipefail; +# +thisFile="$(readlink -f "${0}")"; +thisFilePath="$(dirname "${thisFile}")"; + +for path in $(ls -1d {{ haproxy_letsencrypt_ssl_src_path }}/*/); do + cert="$(basename ${path})"; + + prefix="100"; + removePrefix="000"; + + if [ "${cert}" == "{{ haproxy_letsencrypt_ssl_first_cert }}" ]; then + prefix="000"; + removePrefix="100"; + fi + + ocspUrl="$(openssl x509 -noout -ocsp_uri -in ${path}{{ haproxy_letsencrypt_ssl_cert_name }})"; + + openssl ocsp -no_nonce -respout "{{ haproxy_global_crt_base }}/${prefix}-${cert}.ocsp" \ + -issuer "${path}{{ haproxy_letsencrypt_ssl_chain_name }}" \ + -verify_other "${path}{{ haproxy_letsencrypt_ssl_chain_name }}" \ + -cert "${path}{{ haproxy_letsencrypt_ssl_cert_name }}" \ + -url "${ocspUrl}"; + + rm -f "{{ haproxy_global_crt_base }}/${removePrefix}-${cert}.ocsp"; +done + +{% if ansible_service_mgr == 'systemd' %} +systemctl reload haproxy; +{% else %} +service haproxy reload; +{% endif %} diff --git a/templates/usr/local/bin/haproxy-letsencrypt-ssl-deploy.j2 b/templates/usr/local/bin/haproxy-letsencrypt-ssl-deploy.j2 new file mode 100644 index 00000000..f9e2dbc9 --- /dev/null +++ b/templates/usr/local/bin/haproxy-letsencrypt-ssl-deploy.j2 @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# {{ ansible_managed }} +# +# set -x; +set -e; +set -o pipefail; +# +thisFile="$(readlink -f "${0}")"; +thisFilePath="$(dirname "${thisFile}")"; + +for path in $(ls -1d {{ haproxy_letsencrypt_ssl_src_path }}/*/); do + cert="$(basename ${path})"; + + prefix="100"; + removePrefix="000"; + + if [ "${cert}" == "{{ haproxy_letsencrypt_ssl_first_cert }}" ]; then + prefix="000"; + removePrefix="100"; + fi + + cat "${path}{{ haproxy_letsencrypt_ssl_fullchain_name }}" "${path}{{ haproxy_letsencrypt_ssl_privkey_name }}" > "{{ haproxy_global_crt_base }}/${prefix}-${cert}.pem"; + + rm -f "{{ haproxy_global_crt_base }}/${removePrefix}-${cert}.pem"; +done + +{{ haproxy_letsencrypt_ocsp_deploy }}; diff --git a/vars/main.yml b/vars/main.yml index 3d8b2c53..049ad2d2 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -16,3 +16,7 @@ haproxy_dependencies_pre: - dirmngr haproxy_ppa: "ppa:vbernat/haproxy-{{ haproxy_version }}" + +haproxy_letsencrypt_ssl_deploy: /usr/local/bin/haproxy-letsencrypt-ssl-deploy + +haproxy_letsencrypt_ocsp_deploy: /usr/local/bin/haproxy-letsencrypt-ocsp-deploy