Add support for LetsEncrypt-managed certs
Add support for automatic provisioning and renewal of HTTPS certificates via LetsEncrypt. HAProxy now monitors for new/updated certificates, executing a HAProxy reload when the LetsEncrypt certificate is updated. TO-DO: 1. Copying new/updated certificates to other HAProxy nodes 2. Support internal + external certificates 3. Tests Spec is available at: https://etherpad.opendev.org/p/kolla-ansible-letsencrypt-https Implements: blueprint letsencrypt-https Change-Id: I35317ea0343f0db74ddc0e587862e95408e9e106 Depends-On: https://review.opendev.org/#/c/741339
This commit is contained in:
committed by
James Kirsch
parent
3da5cd15bd
commit
0cff76d85a
@@ -352,6 +352,8 @@ kibana_server_port: "5601"
|
||||
|
||||
kuryr_port: "23750"
|
||||
|
||||
letsencrypt_acme_port: "8081"
|
||||
|
||||
magnum_api_port: "9511"
|
||||
|
||||
manila_api_port: "8786"
|
||||
@@ -573,6 +575,8 @@ enable_outward_rabbitmq: "{{ enable_murano | bool }}"
|
||||
# with things that the clients are not aware of is generally wrong
|
||||
enable_haproxy_memcached: "no"
|
||||
|
||||
enable_letsencrypt: no
|
||||
|
||||
# Additional optional OpenStack features and services are specified here
|
||||
enable_aodh: "no"
|
||||
enable_barbican: "no"
|
||||
@@ -816,6 +820,11 @@ kolla_tls_backend_key: "{{ kolla_certificates_dir }}/backend-key.pem"
|
||||
#####################
|
||||
acme_client_servers: []
|
||||
|
||||
####################
|
||||
# LetsEncrypt options
|
||||
####################
|
||||
letsencrypt_email:
|
||||
|
||||
####################
|
||||
# Kibana options
|
||||
####################
|
||||
|
||||
@@ -783,3 +783,9 @@ ovn-database
|
||||
|
||||
[ovn-sb-db:children]
|
||||
ovn-database
|
||||
|
||||
[letsencrypt:children]
|
||||
haproxy
|
||||
|
||||
[letsencrypt:children]
|
||||
letsencrypt
|
||||
|
||||
@@ -801,3 +801,9 @@ ovn-database
|
||||
|
||||
[ovn-sb-db:children]
|
||||
ovn-database
|
||||
|
||||
[letsencrypt:children]
|
||||
haproxy
|
||||
|
||||
[letsencrypt:children]
|
||||
letsencrypt
|
||||
|
||||
@@ -53,6 +53,7 @@ haproxy_default_volumes:
|
||||
- "{{ node_config_directory }}/haproxy/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "{{ '/etc/timezone:/etc/timezone:ro' if ansible_os_family == 'Debian' else '' }}"
|
||||
- "letsencrypt_certs:/etc/letsencrypt:ro"
|
||||
- "haproxy_socket:/var/lib/kolla/haproxy/"
|
||||
keepalived_default_volumes:
|
||||
- "{{ node_config_directory }}/keepalived/:{{ container_config_directory }}/:ro"
|
||||
|
||||
@@ -96,15 +96,13 @@
|
||||
service: "{{ haproxy_services['haproxy'] }}"
|
||||
copy:
|
||||
src: "{{ kolla_external_fqdn_cert }}"
|
||||
dest: "{{ node_config_directory }}/haproxy/{{ item }}"
|
||||
dest: "{{ node_config_directory }}/haproxy/haproxy.pem"
|
||||
mode: "0660"
|
||||
become: true
|
||||
when:
|
||||
- kolla_enable_tls_external | bool
|
||||
- inventory_hostname in groups[service.group]
|
||||
- service.enabled | bool
|
||||
with_items:
|
||||
- "haproxy.pem"
|
||||
notify:
|
||||
- Restart haproxy container
|
||||
|
||||
@@ -113,15 +111,13 @@
|
||||
service: "{{ haproxy_services['haproxy'] }}"
|
||||
copy:
|
||||
src: "{{ kolla_internal_fqdn_cert }}"
|
||||
dest: "{{ node_config_directory }}/haproxy/{{ item }}"
|
||||
dest: "{{ node_config_directory }}/haproxy/haproxy-internal.pem"
|
||||
mode: "0660"
|
||||
become: true
|
||||
when:
|
||||
- kolla_enable_tls_internal | bool
|
||||
- inventory_hostname in groups[service.group]
|
||||
- service.enabled | bool
|
||||
with_items:
|
||||
- "haproxy-internal.pem"
|
||||
notify:
|
||||
- Restart haproxy container
|
||||
|
||||
@@ -146,3 +142,20 @@
|
||||
- "haproxy_run.sh.j2"
|
||||
notify:
|
||||
- Restart haproxy container
|
||||
|
||||
- name: Copying new certificate monitoring script
|
||||
vars:
|
||||
service: "{{ haproxy_services['haproxy'] }}"
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ node_config_directory }}/haproxy/{{ item.dest }}"
|
||||
mode: "{{ item.mode | default('0660') }}"
|
||||
become: true
|
||||
with_items:
|
||||
- { src: "check-for-new-certificates.sh.j2", dest: "check-for-new-certificates.sh", mode: "0770" }
|
||||
- { src: "crontab.j2", dest: "crontab", mode: "0770" }
|
||||
when:
|
||||
- inventory_hostname in groups[service.group]
|
||||
- service.enabled | bool
|
||||
notify:
|
||||
- Restart haproxy container
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
le_base=/etc/letsencrypt/live
|
||||
|
||||
for cert in haproxy.pem haproxy-internal.pem
|
||||
do
|
||||
if [[ "$cert" == "haproxy.pem" ]]; then
|
||||
domain={{ kolla_external_fqdn }}
|
||||
else
|
||||
domain={{ kolla_internal_fqdn }}
|
||||
fi
|
||||
|
||||
if [[ -d "$le_base" ]]; then
|
||||
ha_cert=/etc/haproxy/$cert
|
||||
le_cert=$le_base/$domain/$cert
|
||||
|
||||
# check if the lets encrypt certificate has been updated
|
||||
if ! cmp "$ha_cert" "$le_cert" > /dev/null 2>&1 ; then
|
||||
echo "Backing up $cert"
|
||||
datetime="$(date '+%Y-%m-%d_%H:%M:%S')"
|
||||
ha_cert_back="${ha_cert}_${datetime}"
|
||||
echo "$ha_cert_back"
|
||||
cp $ha_cert $ha_cert_back
|
||||
|
||||
echo "Updating $ha_cert"
|
||||
cp $le_cert $ha_cert
|
||||
|
||||
ha_parent_pid=$(ps -ef | grep "haproxy_run\.sh" | awk '{print $2}')
|
||||
ha_pid=$(ps --no-headers --ppid $ha_parent_pid -o pid | awk '{print $1}')
|
||||
echo "Reloading HaProxy - process ${ha_pid}"
|
||||
kill -USR2 $ha_pid
|
||||
|
||||
#TODO distribute certs to HAProxy instance on other servers
|
||||
else
|
||||
echo "Same certificates, not updating"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
2
ansible/roles/haproxy/templates/crontab.j2
Normal file
2
ansible/roles/haproxy/templates/crontab.j2
Normal file
@@ -0,0 +1,2 @@
|
||||
* * * * * /usr/bin/check-for-new-certificates.sh >> /var/log/kolla/cron.log 2>&1
|
||||
# Don't remove the empty line at the end of this file. It is required to run the cron job
|
||||
@@ -1,3 +1,4 @@
|
||||
{% set cron_path = '/var/spool/cron/crontabs/root' if kolla_base_distro in ['ubuntu', 'debian'] else '/var/spool/cron/root' %}
|
||||
{
|
||||
"command": "/etc/haproxy/haproxy_run.sh",
|
||||
"config_files": [
|
||||
@@ -23,7 +24,7 @@
|
||||
"source": "{{ container_config_directory }}/haproxy.pem",
|
||||
"dest": "/etc/haproxy/haproxy.pem",
|
||||
"owner": "root",
|
||||
"perm": "0600",
|
||||
"perm": "0700",
|
||||
"optional": {{ (not kolla_enable_tls_external | bool) | string | lower }}
|
||||
},
|
||||
{
|
||||
@@ -32,6 +33,20 @@
|
||||
"owner": "root",
|
||||
"perm": "0600",
|
||||
"optional": {{ (not kolla_enable_tls_internal | bool) | string | lower }}
|
||||
}
|
||||
}{% if enable_letsencrypt | bool %},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/check-for-new-certificates.sh",
|
||||
"dest": "/usr/bin/check-for-new-certificates.sh",
|
||||
"owner": "root",
|
||||
"perm": "0770"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/crontab",
|
||||
"dest": "{{ cron_path }}",
|
||||
"owner": "root",
|
||||
"perm": "0600"
|
||||
}{% endif %}
|
||||
],
|
||||
"permissions": [
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
# We need to run haproxy with one `-f` for each service, because including an
|
||||
# entire config directory was not a feature until version 1.7 of HAProxy.
|
||||
# So, append "-f $cfg" to the haproxy command for each service file.
|
||||
# This will run haproxy_cmd *exactly once*.
|
||||
find /etc/haproxy/services.d/ -mindepth 1 -print0 | \
|
||||
xargs -0 -Icfg echo -f cfg | \
|
||||
xargs /usr/sbin/haproxy -W -db -p /run/haproxy.pid -f /etc/haproxy/haproxy.cfg
|
||||
{% if enable_letsencrypt | bool %}
|
||||
echo "start cron to monitor for Let's Encrypt certificates"
|
||||
{% set cron_cmd = 'cron' if kolla_base_distro in ['ubuntu', 'debian'] else 'crond' %}
|
||||
{{ cron_cmd }}
|
||||
{% endif %}
|
||||
|
||||
echo "start haproxy"
|
||||
|
||||
/usr/sbin/haproxy -W -db -p /run/haproxy.pid -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/services.d/
|
||||
|
||||
56
ansible/roles/letsencrypt/defaults/main.yml
Normal file
56
ansible/roles/letsencrypt/defaults/main.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
project_name: "letsencrypt"
|
||||
|
||||
letsencrypt_services:
|
||||
letsencrypt-acme:
|
||||
container_name: letsencrypt_acme
|
||||
group: letsencrypt
|
||||
enabled: true
|
||||
image: "{{ letsencrypt_acme_image_full }}"
|
||||
volumes: "{{ letsencrypt_acme_default_volumes + letsencrypt_acme_extra_volumes }}"
|
||||
dimensions: "{{ letsencrypt_acme_dimensions }}"
|
||||
haproxy:
|
||||
letsencrypt_acme_server:
|
||||
enabled: "{{ enable_letsencrypt }}"
|
||||
mode: "http"
|
||||
external: false
|
||||
port: "{{ letsencrypt_acme_port }}"
|
||||
letsencrypt-certbot:
|
||||
container_name: letsencrypt_certbot
|
||||
group: letsencrypt
|
||||
enabled: true
|
||||
image: "{{ letsencrypt_certbot_image_full }}"
|
||||
volumes: "{{ letsencrypt_certbot_default_volumes + letsencrypt_certbot_extra_volumes }}"
|
||||
dimensions: "{{ letsencrypt_certbot_dimensions }}"
|
||||
|
||||
##############
|
||||
# LetsEncrypt
|
||||
##############
|
||||
letsencrypt_install_type: "{{ kolla_install_type }}"
|
||||
letsencrypt_logging_debug: "{{ openstack_logging_debug }}"
|
||||
|
||||
letsencrypt_acme_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ letsencrypt_install_type }}-letsencrypt"
|
||||
letsencrypt_tag: "{{ openstack_tag }}"
|
||||
letsencrypt_acme_image_full: "{{ letsencrypt_acme_image }}:{{ letsencrypt_tag }}"
|
||||
|
||||
letsencrypt_certbot_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ letsencrypt_install_type }}-letsencrypt"
|
||||
letsencrypt_certbot_tag: "{{ openstack_tag }}"
|
||||
letsencrypt_certbot_image_full: "{{ letsencrypt_certbot_image }}:{{ letsencrypt_certbot_tag }}"
|
||||
|
||||
letsencrypt_acme_dimensions: "{{ default_container_dimensions }}"
|
||||
letsencrypt_certbot_dimensions: "{{ default_container_dimensions }}"
|
||||
|
||||
letsencrypt_acme_default_volumes:
|
||||
- "{{ node_config_directory }}/letsencrypt-acme/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "letsencrypt_acme_webroot:/www/data"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
letsencrypt_acme_extra_volumes: "{{ default_extra_volumes }}"
|
||||
|
||||
letsencrypt_certbot_default_volumes:
|
||||
- "{{ node_config_directory }}/letsencrypt-certbot/:{{ container_config_directory }}/:ro"
|
||||
- "/etc/localtime:/etc/localtime:ro"
|
||||
- "letsencrypt_certs:/etc/letsencrypt"
|
||||
- "letsencrypt_acme_webroot:/www/data"
|
||||
- "kolla_logs:/var/log/kolla/"
|
||||
letsencrypt_certbot_extra_volumes: "{{ default_extra_volumes }}"
|
||||
30
ansible/roles/letsencrypt/handlers/main.yml
Normal file
30
ansible/roles/letsencrypt/handlers/main.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
- name: Restart letsencrypt-acme container
|
||||
vars:
|
||||
service_name: "letsencrypt-acme"
|
||||
service: "{{ letsencrypt_services[service_name] }}"
|
||||
become: true
|
||||
kolla_docker:
|
||||
action: "recreate_or_restart_container"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
name: "{{ service.container_name }}"
|
||||
image: "{{ service.image }}"
|
||||
volumes: "{{ service.volumes }}"
|
||||
dimensions: "{{ service.dimensions }}"
|
||||
when:
|
||||
- kolla_action != "config"
|
||||
|
||||
- name: Restart letsencrypt-certbot container
|
||||
vars:
|
||||
service_name: "letsencrypt-certbot"
|
||||
service: "{{ letsencrypt_services[service_name] }}"
|
||||
become: true
|
||||
kolla_docker:
|
||||
action: "recreate_or_restart_container"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
name: "{{ service.container_name }}"
|
||||
image: "{{ service.image }}"
|
||||
volumes: "{{ service.volumes }}"
|
||||
dimensions: "{{ service.dimensions }}"
|
||||
when:
|
||||
- kolla_action != "config"
|
||||
3
ansible/roles/letsencrypt/meta/main.yml
Normal file
3
ansible/roles/letsencrypt/meta/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
dependencies:
|
||||
- { role: common }
|
||||
16
ansible/roles/letsencrypt/tasks/check-containers.yml
Normal file
16
ansible/roles/letsencrypt/tasks/check-containers.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Check LetsEncrypt containers
|
||||
become: true
|
||||
kolla_docker:
|
||||
action: "compare_container"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
name: "{{ item.value.container_name }}"
|
||||
image: "{{ item.value.image }}"
|
||||
volumes: "{{ item.value.volumes }}"
|
||||
dimensions: "{{ item.value.dimensions }}"
|
||||
when:
|
||||
- inventory_hostname in groups[item.value.group]
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ letsencrypt_services }}"
|
||||
notify:
|
||||
- "Restart {{ item.key }} container"
|
||||
1
ansible/roles/letsencrypt/tasks/check.yml
Normal file
1
ansible/roles/letsencrypt/tasks/check.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
||||
65
ansible/roles/letsencrypt/tasks/config.yml
Normal file
65
ansible/roles/letsencrypt/tasks/config.yml
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
- name: Ensuring config directories exist
|
||||
file:
|
||||
path: "{{ node_config_directory }}/{{ item.key }}"
|
||||
state: "directory"
|
||||
owner: "{{ config_owner_user }}"
|
||||
group: "{{ config_owner_group }}"
|
||||
mode: "0770"
|
||||
become: true
|
||||
when:
|
||||
- inventory_hostname in groups[item.value.group]
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ letsencrypt_services }}"
|
||||
|
||||
- name: Copying over config.json files
|
||||
template:
|
||||
src: "{{ item.key }}.json.j2"
|
||||
dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
|
||||
mode: "0660"
|
||||
become: true
|
||||
when:
|
||||
- inventory_hostname in groups[item.value.group]
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ letsencrypt_services }}"
|
||||
notify:
|
||||
- Restart {{ item.key }} container
|
||||
|
||||
- name: Copying files for letsencrypt-acme
|
||||
vars:
|
||||
letsencrypt_acme: "{{ letsencrypt_services['letsencrypt-acme'] }}"
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ node_config_directory }}/letsencrypt-acme/{{ item.dest }}"
|
||||
mode: "{{ item.mode | default('0660') }}"
|
||||
become: true
|
||||
with_items:
|
||||
- { src: "certbot-apache.conf.j2", dest: "certbot-apache.conf" }
|
||||
- { src: "apache.sh.j2", dest: "apache.sh" }
|
||||
when:
|
||||
- inventory_hostname in groups[letsencrypt_acme.group]
|
||||
- letsencrypt_acme.enabled | bool
|
||||
notify:
|
||||
- Restart letsencrypt-acme container
|
||||
|
||||
- name: Copying files for letsencrypt-certbot
|
||||
vars:
|
||||
letsencrypt_certbot: "{{ letsencrypt_services['letsencrypt-certbot'] }}"
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ node_config_directory }}/letsencrypt-certbot/{{ item.dest }}"
|
||||
mode: "{{ item.mode | default('0660') }}"
|
||||
become: true
|
||||
with_items:
|
||||
- { src: "letsencrypt.ini.j2", dest: "letsencrypt.ini" }
|
||||
- { src: "certbot-renew.sh.j2", dest: "certbot-renew.sh", mode: "0770" }
|
||||
- { src: "certbot.sh.j2", dest: "certbot.sh", mode: "0770" }
|
||||
- { src: "crontab.j2", dest: "crontab", mode: "0770" }
|
||||
when:
|
||||
- inventory_hostname in groups[letsencrypt_certbot.group]
|
||||
- letsencrypt_certbot.enabled | bool
|
||||
notify:
|
||||
- Restart letsencrypt-certbot container
|
||||
|
||||
- include_tasks: check-containers.yml
|
||||
when: kolla_action != "config"
|
||||
2
ansible/roles/letsencrypt/tasks/deploy-containers.yml
Normal file
2
ansible/roles/letsencrypt/tasks/deploy-containers.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- import_tasks: check-containers.yml
|
||||
5
ansible/roles/letsencrypt/tasks/deploy.yml
Normal file
5
ansible/roles/letsencrypt/tasks/deploy.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
- include_tasks: config.yml
|
||||
|
||||
- name: Flush handlers
|
||||
meta: flush_handlers
|
||||
7
ansible/roles/letsencrypt/tasks/loadbalancer.yml
Normal file
7
ansible/roles/letsencrypt/tasks/loadbalancer.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
- name: "Configure haproxy for {{ project_name }}"
|
||||
import_role:
|
||||
role: haproxy-config
|
||||
vars:
|
||||
project_services: "{{ letsencrypt_services }}"
|
||||
tags: always
|
||||
2
ansible/roles/letsencrypt/tasks/main.yml
Normal file
2
ansible/roles/letsencrypt/tasks/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- include_tasks: "{{ kolla_action }}.yml"
|
||||
18
ansible/roles/letsencrypt/tasks/precheck.yml
Normal file
18
ansible/roles/letsencrypt/tasks/precheck.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
- name: Get container facts
|
||||
become: true
|
||||
kolla_container_facts:
|
||||
name:
|
||||
- letsencrypt_acme
|
||||
register: container_facts
|
||||
|
||||
- name: Checking free port for LetsEncrypt server
|
||||
wait_for:
|
||||
host: "{{ api_interface_address }}"
|
||||
port: "{{ letsencrypt_acme_port }}"
|
||||
connect_timeout: 1
|
||||
timeout: 1
|
||||
state: stopped
|
||||
when:
|
||||
- container_facts['letsencrypt_acme'] is not defined
|
||||
- inventory_hostname in groups['letsencrypt_acme']
|
||||
11
ansible/roles/letsencrypt/tasks/pull.yml
Normal file
11
ansible/roles/letsencrypt/tasks/pull.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Pulling LetsEncrypt images
|
||||
become: true
|
||||
kolla_docker:
|
||||
action: "pull_image"
|
||||
common_options: "{{ docker_common_options }}"
|
||||
image: "{{ item.value.image }}"
|
||||
when:
|
||||
- inventory_hostname in groups[item.value.group]
|
||||
- item.value.enabled | bool
|
||||
with_dict: "{{ letsencrypt_services }}"
|
||||
2
ansible/roles/letsencrypt/tasks/reconfigure.yml
Normal file
2
ansible/roles/letsencrypt/tasks/reconfigure.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- include_tasks: deploy.yml
|
||||
6
ansible/roles/letsencrypt/tasks/stop.yml
Normal file
6
ansible/roles/letsencrypt/tasks/stop.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
- import_role:
|
||||
role: service-stop
|
||||
vars:
|
||||
project_services: "{{ letsencrypt_services }}"
|
||||
service_name: "{{ project_name }}"
|
||||
2
ansible/roles/letsencrypt/tasks/upgrade.yml
Normal file
2
ansible/roles/letsencrypt/tasks/upgrade.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- include_tasks: deploy.yml
|
||||
14
ansible/roles/letsencrypt/templates/apache.sh.j2
Normal file
14
ansible/roles/letsencrypt/templates/apache.sh.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
{% set apache_binary = 'apache2' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd' %}
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
echo "create domain directories"
|
||||
|
||||
mkdir -p /www/data/{{ kolla_external_fqdn }}
|
||||
mkdir -p /www/data/{{ kolla_internal_fqdn }}
|
||||
|
||||
echo "Start apache"
|
||||
|
||||
/usr/sbin/{{ apache_binary }} -DFOREGROUND
|
||||
43
ansible/roles/letsencrypt/templates/certbot-apache.conf.j2
Normal file
43
ansible/roles/letsencrypt/templates/certbot-apache.conf.j2
Normal file
@@ -0,0 +1,43 @@
|
||||
{% set letsencrypt_log_dir = '/var/log/kolla/letsencrypt' %}
|
||||
{% set binary_path = '/usr/bin' if letsencrypt_install_type == 'binary' else '/var/lib/kolla/venv/bin' %}
|
||||
Listen {{ api_interface_address | put_address_in_context('url') }}:{{ letsencrypt_acme_port }}
|
||||
|
||||
ServerSignature Off
|
||||
ServerTokens Prod
|
||||
TraceEnable off
|
||||
KeepAliveTimeout {{ kolla_httpd_keep_alive }}
|
||||
|
||||
ErrorLog "{{ letsencrypt_log_dir }}/acme-apache-error.log"
|
||||
<IfModule log_config_module>
|
||||
CustomLog "{{ letsencrypt_log_dir }}/acme-apache-access.log" common
|
||||
</IfModule>
|
||||
|
||||
{% if letsencrypt_logging_debug | bool %}
|
||||
LogLevel info
|
||||
{% endif %}
|
||||
|
||||
<Directory "/www/data/{{ kolla_external_fqdn }}">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory "/www/data/{{ kolla_internal_fqdn }}">
|
||||
AllowOverride None
|
||||
Options None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<VirtualHost *:{{ letsencrypt_acme_port }}>
|
||||
DocumentRoot "/www/data/{{ kolla_external_fqdn }}"
|
||||
ServerName {{ kolla_external_fqdn }}
|
||||
ErrorLog "{{ letsencrypt_log_dir }}/{{ kolla_external_fqdn }}-error_log"
|
||||
TransferLog "{{ letsencrypt_log_dir }}/{{ kolla_external_fqdn }}-access_log"
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:{{ letsencrypt_acme_port }}>
|
||||
DocumentRoot "/www/data/{{ kolla_internal_fqdn }}"
|
||||
ServerName {{ kolla_internal_fqdn }}
|
||||
ErrorLog "{{ letsencrypt_log_dir }}/{{ kolla_internal_fqdn }}-error_log"
|
||||
TransferLog "{{ letsencrypt_log_dir }}/{{ kolla_internal_fqdn }}-access_log"
|
||||
</VirtualHost>
|
||||
12
ansible/roles/letsencrypt/templates/certbot-renew.sh.j2
Normal file
12
ansible/roles/letsencrypt/templates/certbot-renew.sh.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
certbot renew
|
||||
|
||||
# merging certs and keys in case they were updated
|
||||
le_base=/etc/letsencrypt/live
|
||||
|
||||
cat "$le_base/{{ kolla_external_fqdn }}/fullchain.pem" "$le_base/{{ kolla_external_fqdn }}/privkey.pem" \
|
||||
> "$le_base/{{ kolla_external_fqdn }}/haproxy.pem"
|
||||
|
||||
cat "$le_base/{{ kolla_internal_fqdn }}/fullchain.pem" "$le_base/{{ kolla_internal_fqdn }}/privkey.pem" \
|
||||
> "$le_base/{{ kolla_internal_fqdn }}/haproxy-internal.pem"
|
||||
27
ansible/roles/letsencrypt/templates/certbot.sh.j2
Normal file
27
ansible/roles/letsencrypt/templates/certbot.sh.j2
Normal file
@@ -0,0 +1,27 @@
|
||||
le_base=/etc/letsencrypt/live
|
||||
if [ ! -f "$le_base/{{ kolla_external_fqdn }}/haproxy.pem" ]; then
|
||||
echo "execute cert bot for domain: {{ kolla_external_fqdn }}"
|
||||
certbot certonly -v --webroot -w /www/data/{{ kolla_external_fqdn }} --no-eff-email --agree-tos -d {{ kolla_external_fqdn }} --cert-name {{ kolla_external_fqdn }}
|
||||
# create single certificate
|
||||
echo "merging certs and keys"
|
||||
cat "$le_base/{{ kolla_external_fqdn }}/fullchain.pem" "$le_base/{{ kolla_external_fqdn }}/privkey.pem" \
|
||||
> "$le_base/{{ kolla_external_fqdn }}/haproxy.pem"
|
||||
else
|
||||
echo "LetsEncrypt certificate already generated for domain: {{ kolla_external_fqdn }}"
|
||||
fi
|
||||
|
||||
if [ ! -f "$le_base/{{ kolla_internal_fqdn }}/haproxy-internal.pem" ]; then
|
||||
echo "execute cert bot for domain: {{ kolla_internal_fqdn }}"
|
||||
certbot certonly -v --webroot -w /www/data/{{ kolla_internal_fqdn }} --no-eff-email --agree-tos -d {{ kolla_internal_fqdn }} --cert-name {{ kolla_internal_fqdn }}
|
||||
# create single certificate
|
||||
echo "merging certs and keys"
|
||||
cat "$le_base/{{ kolla_internal_fqdn }}/fullchain.pem" "$le_base/{{ kolla_internal_fqdn }}/privkey.pem" \
|
||||
> "$le_base/{{ kolla_internal_fqdn }}/haproxy-internal.pem"
|
||||
else
|
||||
echo "LetsEncrypt certificate already generated for domain: {{ kolla_internal_fqdn }}"
|
||||
fi
|
||||
|
||||
# start cron job in foreground for certificate renewal
|
||||
echo "start cron"
|
||||
{% set cron_cmd = 'cron -f' if kolla_base_distro in ['ubuntu', 'debian'] else 'crond -s -n' %}
|
||||
{{ cron_cmd }}
|
||||
3
ansible/roles/letsencrypt/templates/crontab.j2
Normal file
3
ansible/roles/letsencrypt/templates/crontab.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
# Will run certbot renew every 12 hours
|
||||
0 */12 * * * /usr/sbin/certbot-renew.sh >> /var/log/kolla/cron.log 2>&1
|
||||
# Don't remove the empty line at the end of this file. It is required to run the cron job
|
||||
19
ansible/roles/letsencrypt/templates/letsencrypt-acme.json.j2
Normal file
19
ansible/roles/letsencrypt/templates/letsencrypt-acme.json.j2
Normal file
@@ -0,0 +1,19 @@
|
||||
{% set letsencrypt_apache_dir = 'apache2/conf-enabled' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd/conf.d' %}
|
||||
{
|
||||
"command": "/usr/bin/apache.sh",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/certbot-apache.conf",
|
||||
"dest": "/etc/{{ letsencrypt_apache_dir }}/certbot-apache.conf",
|
||||
"owner": "letsencrypt",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/apache.sh",
|
||||
"dest": "/usr/bin/apache.sh",
|
||||
"owner": "root",
|
||||
"perm": "0700"
|
||||
}
|
||||
],
|
||||
"permissions": []
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{% set cron_path = '/var/spool/cron/crontabs/root' if kolla_base_distro in ['ubuntu', 'debian'] else '/var/spool/cron/root' %}
|
||||
{
|
||||
"command": "/usr/bin/certbot.sh",
|
||||
"config_files": [
|
||||
{
|
||||
"source": "{{ container_config_directory }}/letsencrypt.ini",
|
||||
"dest": "/etc/letsencrypt/cli.ini",
|
||||
"owner": "root",
|
||||
"perm": "0600"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/certbot-renew.sh",
|
||||
"dest": "/usr/bin/certbot-renew.sh",
|
||||
"owner": "root",
|
||||
"perm": "0700"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/certbot.sh",
|
||||
"dest": "/usr/bin/certbot.sh",
|
||||
"owner": "root",
|
||||
"perm": "0700"
|
||||
},
|
||||
{
|
||||
"source": "{{ container_config_directory }}/crontab",
|
||||
"dest": "{{ cron_path }}",
|
||||
"owner": "root",
|
||||
"perm": "0600"
|
||||
}
|
||||
],
|
||||
"permissions": []
|
||||
}
|
||||
3
ansible/roles/letsencrypt/templates/letsencrypt.ini.j2
Normal file
3
ansible/roles/letsencrypt/templates/letsencrypt.ini.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
rsa-key-size = 4096
|
||||
|
||||
email = {{ letsencrypt_email }}
|
||||
@@ -43,6 +43,7 @@
|
||||
- enable_keystone_{{ enable_keystone | bool }}
|
||||
- enable_kibana_{{ enable_kibana | bool }}
|
||||
- enable_kuryr_{{ enable_kuryr | bool }}
|
||||
- enable_letsencrypt_{{ enable_letsencrypt | bool }}
|
||||
- enable_magnum_{{ enable_magnum | bool }}
|
||||
- enable_manila_{{ enable_manila | bool }}
|
||||
- enable_mariadb_{{ enable_mariadb | bool }}
|
||||
@@ -224,6 +225,11 @@
|
||||
tasks_from: loadbalancer
|
||||
tags: kibana
|
||||
when: enable_kibana | bool
|
||||
- include_role:
|
||||
name: letsencrypt
|
||||
tasks_from: loadbalancer
|
||||
tags: letsencrypt
|
||||
when: enable_letsencrypt | bool
|
||||
- include_role:
|
||||
name: magnum
|
||||
tasks_from: loadbalancer
|
||||
@@ -1205,3 +1211,14 @@
|
||||
- { role: masakari,
|
||||
tags: masakari,
|
||||
when: enable_masakari | bool }
|
||||
|
||||
- name: Apply role letsencrypt
|
||||
gather_facts: false
|
||||
hosts:
|
||||
- letsencrypt
|
||||
- '&enable_letsencrypt_True'
|
||||
serial: '{{ kolla_serial|default("0") }}'
|
||||
roles:
|
||||
- { role: letsencrypt,
|
||||
tags: letsencrypt,
|
||||
when: enable_letsencrypt | bool }
|
||||
|
||||
Reference in New Issue
Block a user