diff --git a/defaults/main.yml b/defaults/main.yml index 83d81a5..10b2c59 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -71,6 +71,15 @@ haproxy_ssl_ca_cert: /etc/ssl/certs/haproxy-ca.pem haproxy_ssl_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT/CN={{ external_lb_vip_address }}/subjectAltName=IP.1={{ external_lb_vip_address }}" haproxy_ssl_cipher_suite: "{{ ssl_cipher_suite | default('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS') }}" haproxy_ssl_bind_options: "force-tlsv12" +# activate letsencrypt option +haproxy_ssl_letsencrypt_enable: false +haproxy_ssl_letsencrypt_email: "example@example.com" +haproxy_ssl_letsencrypt_download_url: "https://dl.eff.org/certbot-auto" +haproxy_ssl_letsencrypt_config_path: "/etc/letsencrypt/live" +haproxy_ssl_letsencrypt_install_path: "/opt/letsencrypt" +haproxy_ssl_letsencrypt_cron_minute: "0" +haproxy_ssl_letsencrypt_cron_hour: "0" +haproxy_ssl_letsencrypt_cron_weekday: "0" # hatop extra package URL and checksum haproxy_hatop_download_url: "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/hatop/hatop-0.7.7.tar.gz" diff --git a/doc/source/configure-haproxy.rst b/doc/source/configure-haproxy.rst index 2d4ce93..f7650f1 100644 --- a/doc/source/configure-haproxy.rst +++ b/doc/source/configure-haproxy.rst @@ -143,6 +143,25 @@ be folded and formatted at 64 characters long. Single line certificates will not be accepted by HAProxy and will result in SSL validation failures. Please have a look here for information on `converting your certificate to various formats `_. +If you want to use `LetsEncrypt SSL Service `_ +you can activate the feature by providing the following configuration in +``/etc/openstack_deploy/user_variables.yml``. Note that this requires +that ``external_lb_vip_address`` in +``/etc/openstack_deploy/openstack_user_config.yml`` is set to the +external DNS address. + +.. code-block:: yaml + + haproxy_ssl_letsencrypt_enable: true + haproxy_ssl_letsencrypt_email: example@example.com + +.. warning:: + + There is no certificate distribution implementation at this time, so + this will only work for a single haproxy-server environment. The + renewal is automatically handled via CRON and currently will shut + down haproxy briefly during the certificate renewal. The + haproxy shutdown/restart will result in a brief service interruption. .. _Securing services with SSL certificates: http://docs.openstack.org/project-deploy-guide/openstack-ansible/draft/app-advanced-config-sslcertificates.html diff --git a/releasenotes/notes/letsencrypt-ssl-certification-129a80cb88d8e6ff.yaml b/releasenotes/notes/letsencrypt-ssl-certification-129a80cb88d8e6ff.yaml new file mode 100644 index 0000000..f3996eb --- /dev/null +++ b/releasenotes/notes/letsencrypt-ssl-certification-129a80cb88d8e6ff.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + If Horizon dashboard of OSA installation has a public FQDN, is it + now possible to use LetsEncrypt certification service. Certificate + will be generated within HAProxy installation and a cron entry to + renew the certificate daily will be setup. + Note that there is no certificate distribution implementation at + this time, so this will only work for a single haproxy-server + environment. diff --git a/tasks/haproxy_ssl.yml b/tasks/haproxy_ssl.yml index 9aec2e9..7eae2d0 100644 --- a/tasks/haproxy_ssl.yml +++ b/tasks/haproxy_ssl.yml @@ -23,6 +23,13 @@ - include_tasks: haproxy_ssl_self_signed.yml when: - haproxy_ssl | bool + - not haproxy_ssl_letsencrypt_enable | bool + - haproxy_user_ssl_cert is not defined or haproxy_user_ssl_key is not defined + +- include_tasks: haproxy_ssl_letsencrypt.yml + when: + - haproxy_ssl | bool + - haproxy_ssl_letsencrypt_enable | bool - haproxy_user_ssl_cert is not defined or haproxy_user_ssl_key is not defined - include_tasks: haproxy_ssl_user_provided.yml diff --git a/tasks/haproxy_ssl_letsencrypt.yml b/tasks/haproxy_ssl_letsencrypt.yml new file mode 100644 index 0000000..1489ae3 --- /dev/null +++ b/tasks/haproxy_ssl_letsencrypt.yml @@ -0,0 +1,79 @@ +--- +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Ensure haproxy_ssl_letsencrypt_install_path exists + file: + path: "{{ haproxy_ssl_letsencrypt_install_path }}" + state: directory + +- name: Download certbot + get_url: + url: "{{ haproxy_ssl_letsencrypt_download_url }}" + dest: "{{ haproxy_ssl_letsencrypt_install_path }}" + mode: 0755 + register: fetch_url + until: fetch_url is success + retries: 3 + delay: 10 + +- name: Ensure file permissions certbot-auto + file: + path: "{{ haproxy_ssl_letsencrypt_install_path }}/{{ haproxy_ssl_letsencrypt_download_url | basename }}" + +- name: Register Letsencrypt data dir + stat: + path: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ external_lb_vip_address }}" + register: lcdatadir + +- name: Stop haproxy for certbot activity + service: + name: "haproxy" + state: "stopped" + when: lcdatadir.stat.exists == False + +- name: Create ssl cert with certbot + command: > + {{ haproxy_ssl_letsencrypt_install_path }}/{{ haproxy_ssl_letsencrypt_download_url | basename }} certonly + --standalone + --agree-tos + --non-interactive + --text + --rsa-key-size 4096 + --email {{ haproxy_ssl_letsencrypt_email }} + --domains {{ external_lb_vip_address }} + creates: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ external_lb_vip_address }}/fullchain.pem" + +- name: Create new pem file for haproxy + assemble: + src: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ external_lb_vip_address }}" + dest: "/etc/ssl/private/haproxy.pem" + regexp: '(privkey|fullchain).pem$' + notify: + - Restart haproxy + +- name: Create letsencrypt_renew file + template: + src: letsencrypt_renew.j2 + dest: /usr/local/bin/letsencrypt_renew + mode: 0755 + force: yes + +- name: Renew Letsencrypt Cert Cron + cron: + name: "Renew Letsencrypt Cert" + minute: "{{ haproxy_ssl_letsencrypt_cron_minute }}" + hour: "{{ haproxy_ssl_letsencrypt_cron_hour }}" + weekday: "{{ haproxy_ssl_letsencrypt_cron_weekday }}" + job: "/usr/local/bin/letsencrypt_renew" + user: "root" + state: present diff --git a/templates/letsencrypt_renew.j2 b/templates/letsencrypt_renew.j2 new file mode 100644 index 0000000..b259133 --- /dev/null +++ b/templates/letsencrypt_renew.j2 @@ -0,0 +1,11 @@ +#!/bin/bash +# renew cert if required and copy to haproxy destination + +certbot renew \ + --standalone \ + --pre-hook "systemctl stop haproxy" \ + +cat /etc/letsencrypt/live/{{ external_lb_vip_address }}-0001/{fullchain,privkey}.pem \ + > /etc/ssl/private/haproxy.pem + +systemctl restart haproxy