From ee554649bdddde7d7f0384cbf174b25edf615360 Mon Sep 17 00:00:00 2001
From: Damian Dabrowski <damian.dabrowski@cleura.com>
Date: Mon, 17 Apr 2023 21:13:07 +0200
Subject: [PATCH] Add TLS support to octavia backends

By overriding the variable `octavia_backend_ssl: True` HTTPS will
be enabled, disabling HTTP support on the octavia backend api.

The ansible-role-pki is used to generate the required TLS
certificates if this functionality is enabled.

Depends-On: https://review.opendev.org/c/openstack/openstack-ansible/+/879085
Change-Id: Id6c187cad4e444fb83ca1f938bd13bb9b73652b3
---
 defaults/main.yml | 54 +++++++++++++++++++++++++++++++++++++++++++++--
 handlers/main.yml |  1 +
 tasks/main.yml    |  6 +++++-
 3 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/defaults/main.yml b/defaults/main.yml
index fe18e0a6..71d996f9 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -218,6 +218,7 @@ octavia_services:
     uwsgi_overrides: "{{ octavia_api_uwsgi_ini_overrides }}"
     uwsgi_port: "{{ octavia_service_port }}"
     uwsgi_bind_address: "{{ octavia_uwsgi_bind_address }}"
+    uwsgi_tls: "{{ octavia_backend_ssl | ternary(octavia_uwsgi_tls, {}) }}"
   octavia-worker:
     group: octavia-worker
     service_name: octavia-worker
@@ -431,7 +432,9 @@ octavia_wsgi_processes_max: 16
 octavia_wsgi_processes: "{{ [[(ansible_facts['processor_vcpus']//ansible_facts['processor_threads_per_core'])|default(1), 1] | max * 2, octavia_wsgi_processes_max] | min }}"
 octavia_wsgi_threads: 1
 octavia_uwsgi_bind_address: "{{ openstack_service_bind_address | default('0.0.0.0') }}"
-octavia_api_uwsgi_ini_overrides: {}
+octavia_uwsgi_tls:
+  crt: "{{ octavia_api_ssl_cert }}"
+  key: "{{ octavia_api_ssl_key }}"
 
 # Set up the drivers
 octavia_enabled_provider_drivers: "{{ _octavia_enabled_provider_drivers }}"
@@ -500,6 +503,14 @@ octavia_cert_authorities:
     not_after: "+{{ octavia_cert_validity_days }}d"
 
 octavia_cert_certificates:
+  # Communication between haproxy and octavia API
+  - name: "octavia-api_{{ ansible_facts['hostname'] }}"
+    provider: ownca
+    cn: "{{ ansible_facts['hostname'] }}"
+    san: "{{ octavia_api_cert_san }}"
+    signed_by: "{{ octavia_api_intermediate_cert_name }}"
+    condition: "{{ octavia_backend_ssl | bool }}"
+  # Communication between octavia control plane and amphoras
   - name: "octavia_client"
     provider: ownca
     cn: "{{ octavia_cert_client_req_common_name }}"
@@ -512,38 +523,56 @@ octavia_cert_certificates:
     extended_key_usage:
       - clientAuth
       - emailProtection
+    condition: "{{ octavia_generate_certs | bool }}"
 
 # Installation details for SSL certificates
 octavia_cert_install_certificates:
+  # Communication between haproxy and octavia API
+  - src: "{{ octavia_api_user_ssl_cert | default(octavia_cert_certs_dir ~ 'octavia-api_' ~ ansible_facts['hostname'] ~ '-chain.crt') }}"
+    dest: "{{ octavia_api_ssl_cert }}"
+    owner: "{{ octavia_system_user_name }}"
+    group: "{{ octavia_system_user_name }}"
+    mode: "0644"
+    condition: "{{ octavia_backend_ssl | bool }}"
+  - src: "{{ octavia_api_user_ssl_key | default(octavia_cert_keys_dir ~ 'octavia-api_' ~ ansible_facts['hostname'] ~ '.key.pem') }}"
+    dest: "{{ octavia_api_ssl_key }}"
+    owner: "{{ octavia_system_user_name }}"
+    group: "{{ octavia_system_user_name }}"
+    mode: "0600"
+    condition: "{{ octavia_backend_ssl | bool }}"
   # Server CA
   - src: "{{ octavia_ca_certificate | default(octavia_cert_dir ~ '/roots/OctaviaServerRoot/certs/OctaviaServerRoot.crt') }}"
     dest: "/etc/octavia/certs/server_ca.pem"
     owner: "{{ octavia_system_user_name }}"
     group: "{{ octavia_system_group_name }}"
     mode: "0640"
+    condition: "{{ octavia_generate_certs | bool }}"
   - src: "{{ octavia_ca_private_key | default(octavia_cert_dir ~ '/roots/OctaviaServerRoot/private/OctaviaServerRoot.key.pem') }}"
     dest: "/etc/octavia/certs/ca_key.pem"
     owner: "{{ octavia_system_user_name }}"
     group: "{{ octavia_system_group_name }}"
     mode: "0640"
+    condition: "{{ octavia_generate_certs | bool }}"
   # Client CA
   - src: "{{ octavia_client_ca | default(octavia_cert_dir ~ '/roots/OctaviaClientRoot/certs/OctaviaClientRoot.crt') }}"
     dest: "/etc/octavia/certs/client_ca.pem"
     owner: "{{ octavia_system_user_name }}"
     group: "{{ octavia_system_group_name }}"
     mode: "0640"
+    condition: "{{ octavia_generate_certs | bool }}"
   # Client certificate
   - src: "{{ octavia_client_cert | default(octavia_cert_certs_dir ~ '/octavia_client.crt') }}"
     dest: "/etc/octavia/certs/client.pem.crt"
     owner: "{{ octavia_system_user_name }}"
     group: "{{ octavia_system_group_name }}"
     mode: "0640"
+    condition: "{{ octavia_generate_certs | bool }}"
   - src: "{{ octavia_client_key | default(octavia_cert_keys_dir ~ '/octavia_client.key.pem') }}"
     dest: "/etc/octavia/certs/client.pem.key"
     owner: "{{ octavia_system_user_name }}"
     group: "{{ octavia_system_group_name }}"
     mode: "0640"
-
+    condition: "{{ octavia_generate_certs | bool }}"
 
 # Custom client CA
 #octavia_client_ca: "{{ octavia_cert_dir }}/ca_01.pem"
@@ -572,3 +601,24 @@ octavia_num_security_group_rules: "{{ (octavia_num_secgroups|int)*100 }}"
 octavia_octavia_conf_overrides: {}
 octavia_api_paste_ini_overrides: {}
 octavia_policy_overrides: {}
+octavia_api_uwsgi_ini_overrides: {}
+
+###
+### Backend TLS
+###
+
+# Define if communication between haproxy and service backends should be
+# encrypted with TLS.
+octavia_backend_ssl: "{{ openstack_service_backend_ssl | default(False) }}"
+
+# octavia server certificate
+octavia_api_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('ExampleCorpIntermediate') }}"
+octavia_api_cert_san: "{{ openstack_pki_san | default('DNS:' ~ ansible_facts['hostname'] ~ ',IP:' ~ management_address) }}"
+
+# octavia destination files for SSL certificates
+octavia_api_ssl_cert: /etc/octavia/certs/octavia-api.pem
+octavia_api_ssl_key: /etc/octavia/certs/octavia-api.key
+
+# Define user-provided SSL certificates
+#octavia_api_user_ssl_cert: <path to cert on ansible deployment host>
+#octavia_api_user_ssl_key: <path to cert on ansible deployment host>
diff --git a/handlers/main.yml b/handlers/main.yml
index 5461c95f..957ef0e2 100644
--- a/handlers/main.yml
+++ b/handlers/main.yml
@@ -21,3 +21,4 @@
   listen:
     - "venv changed"
     - "systemd service changed"
+    - "cert installed"
diff --git a/tasks/main.yml b/tasks/main.yml
index 411ca2fd..4792b804 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -111,6 +111,10 @@
 - name: Create and install SSL certificates
   include_role:
     name: pki
+    apply:
+      tags:
+        - octavia-config
+        - pki
   vars:
     pki_setup_host: "{{ octavia_cert_setup_host }}"
     pki_dir: "{{ octavia_cert_dir }}"
@@ -122,7 +126,7 @@
     pki_certificates: "{{ octavia_cert_certificates }}"
     pki_install_certificates: "{{ octavia_cert_install_certificates }}"
   when:
-    - octavia_generate_certs | bool
+    - (octavia_generate_certs | bool) or (octavia_backend_ssl | bool)
   tags:
     - always