From d100904f2c42dea3338e5016c46014ee3132807c Mon Sep 17 00:00:00 2001
From: James Kirsch <generalfuzz@gmail.com>
Date: Mon, 6 Jan 2020 20:39:04 -0800
Subject: [PATCH] Generate self signed TLS certificates

Generate both internal and external self signed TLS certificates.
Duplicate the certificate if internal and external VIPs are the same.

Change-Id: I16b345c0b29ff13e042eed8798efe644e0ad2c74
Partially-Implements: blueprint custom-cacerts
---
 ansible/group_vars/all.yml                    |   4 +-
 ansible/roles/certificates/tasks/generate.yml | 165 +++++++++++++-----
 .../templates/openssl-kolla-internal.cnf.j2   |  21 +++
 .../templates/openssl-kolla.cnf.j2            |   1 +
 doc/source/admin/advanced-configuration.rst   |   7 +-
 etc/kolla/globals.yml                         |   4 +-
 ...al-self-signed-certs-c631a9d934d31fac.yaml |  23 +++
 7 files changed, 174 insertions(+), 51 deletions(-)
 create mode 100644 ansible/roles/certificates/templates/openssl-kolla-internal.cnf.j2
 create mode 100644 releasenotes/notes/generate-internal-external-self-signed-certs-c631a9d934d31fac.yaml

diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 5ad1be8706..eaca73e903 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -757,8 +757,8 @@ kolla_enable_tls_internal: "no"
 kolla_enable_tls_external: "{{ kolla_enable_tls_internal if kolla_same_external_internal_vip | bool else 'no' }}"
 kolla_external_fqdn_cert: "{{ node_config }}/certificates/haproxy.pem"
 kolla_internal_fqdn_cert: "{{ node_config }}/certificates/haproxy-internal.pem"
-kolla_external_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca.crt"
-kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca-internal.crt"
+kolla_external_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy.crt"
+kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy-internal.crt"
 kolla_copy_ca_into_containers: "no"
 
 ####################
diff --git a/ansible/roles/certificates/tasks/generate.yml b/ansible/roles/certificates/tasks/generate.yml
index 680cbc3daf..6865c12393 100644
--- a/ansible/roles/certificates/tasks/generate.yml
+++ b/ansible/roles/certificates/tasks/generate.yml
@@ -1,53 +1,130 @@
 ---
-- name: Ensuring config directories exist
-  become: true
+- name: Ensuring private internal directory exist
   file:
-    path: "{{ certificates_dir }}/private"
+    path: "{{ certificates_dir }}/private/internal"
     state: "directory"
     recurse: yes
+    mode: "0770"
 
-- name: Creating SSL configuration file
-  become: true
-  template:
-    src: "{{ item }}.j2"
-    dest: "{{ certificates_dir }}/{{ item }}"
-  with_items:
-    - "openssl-kolla.cnf"
-
-- name: Creating Key
-  become: true
-  command: creates="{{ item }}" openssl genrsa -out {{ item }}
-  with_items:
-    - "{{ certificates_dir }}/private/haproxy.key"
-
-- name: Setting permissions on key
-  become: true
+- name: Ensuring private external directory exist
   file:
-    path: "{{ certificates_dir }}/private/haproxy.key"
-    mode: 0600
-    state: file
+    path: "{{ certificates_dir }}/private/external"
+    state: "directory"
+    recurse: yes
+    mode: "0770"
 
-- name: Creating Server Certificate
-  become: true
-  command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
-    -subj "/C=US/ST=NC/L=RTP/O=kolla/CN={{ kolla_external_fqdn }}" \
-    -config {{ certificates_dir }}/openssl-kolla.cnf \
-    -days 3650 \
-    -extensions v3_req \
-    -key {{ certificates_dir }}/private/haproxy.key \
-    -out {{ item }}
-  with_items:
-    - "{{ certificates_dir }}/private/haproxy.crt"
+- name: Ensuring ca directory exist
+  file:
+    path: "{{ certificates_dir }}/ca"
+    state: "directory"
+    recurse: yes
+    mode: "0770"
 
-- name: Creating CA Certificate File
-  become: true
-  copy:
-    src: "{{ certificates_dir }}/private/haproxy.crt"
-    dest: "{{ kolla_external_fqdn_cacert }}"
+- block:
+    - name: Creating external SSL configuration file
+      template:
+        src: "{{ item }}.j2"
+        dest: "{{ certificates_dir }}/{{ item }}"
+        mode: "0660"
+      with_items:
+        - "openssl-kolla.cnf"
+    - name: Creating external Key
+      command: creates="{{ item }}" openssl genrsa -out {{ item }}
+      with_items:
+        - "{{ certificates_dir }}/private/external/external.key"
+    - name: Setting permissions on external key
+      file:
+        path: "{{ certificates_dir }}/private/external/external.key"
+        mode: "0660"
+        state: file
+    - name: Creating external Server Certificate
+      command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
+        -config {{ certificates_dir }}/openssl-kolla.cnf \
+        -days 3650 \
+        -extensions v3_req \
+        -key {{ certificates_dir }}/private/external/external.key \
+        -out {{ item }}
+      with_items:
+        - "{{ certificates_dir }}/private/external/external.crt"
+    - name: Creating external CA Certificate File
+      copy:
+        src: "{{ certificates_dir }}/private/external/external.crt"
+        dest: "{{ kolla_external_fqdn_cacert }}"
+        mode: "0660"
+    - name: Creating external Server PEM File
+      assemble:
+        src: "{{ certificates_dir }}/private/external"
+        dest: "{{ kolla_external_fqdn_cert }}"
+        mode: "0660"
+  when:
+    - kolla_enable_tls_external | bool
 
-- name: Creating Server PEM File
-  become: true
-  assemble:
-    src: "{{ certificates_dir }}/private"
-    dest: "{{ kolla_external_fqdn_cert }}"
-    mode: 0600
+- block:
+    - name: Copy the external certificate crt to be the internal when internal + external are same network
+      copy:
+        src: "{{ certificates_dir }}/private/external/external.crt"
+        dest: "{{ certificates_dir }}/private/internal/internal.crt"
+        remote_src: yes
+        mode: "0660"
+    - name: Copy the external certificate key to be the internal when internal + external are same network
+      copy:
+        src: "{{ certificates_dir }}/private/external/external.key"
+        dest: "{{ certificates_dir }}/private/internal/internal.key"
+        remote_src: yes
+        mode: "0660"
+    - name: Copy the external PEM file to be the internal when internal + external are same network
+      copy:
+        src: "{{ kolla_external_fqdn_cert }}"
+        dest: "{{ kolla_internal_fqdn_cert }}"
+        remote_src: yes
+        mode: "0660"
+    - name: Copy the external CA Certificate file to be the internal when internal + external are same network
+      copy:
+        src: "{{ kolla_external_fqdn_cacert }}"
+        dest: "{{ kolla_internal_fqdn_cacert }}"
+        remote_src: yes
+        mode: "0660"
+  when:
+    - kolla_enable_tls_external | bool
+    - kolla_enable_tls_internal | bool
+    - kolla_same_external_internal_vip | bool
+
+- block:
+    - name: Creating internal SSL configuration file
+      template:
+        src: "{{ item }}.j2"
+        dest: "{{ certificates_dir }}/{{ item }}"
+        mode: "0660"
+      with_items:
+        - "openssl-kolla-internal.cnf"
+    - name: Creating internal Key
+      command: creates="{{ item }}" openssl genrsa -out {{ item }}
+      with_items:
+        - "{{ certificates_dir }}/private/internal/internal.key"
+    - name: Setting permissions on internal key
+      file:
+        path: "{{ certificates_dir }}/private/internal/internal.key"
+        mode: "0660"
+        state: file
+    - name: Creating internal Server Certificate
+      command: creates="{{ item }}" openssl req -new -nodes -sha256 -x509 \
+        -config {{ certificates_dir }}/openssl-kolla-internal.cnf \
+        -days 3650 \
+        -extensions v3_req \
+        -key {{ certificates_dir }}/private/internal/internal.key \
+        -out {{ item }}
+      with_items:
+        - "{{ certificates_dir }}/private/internal/internal.crt"
+    - name: Creating internal CA Certificate File
+      copy:
+        src: "{{ certificates_dir }}/private/internal/internal.crt"
+        dest: "{{ kolla_internal_fqdn_cacert }}"
+        mode: "0660"
+    - name: Creating internal Server PEM File
+      assemble:
+        src: "{{ certificates_dir }}/private/internal"
+        dest: "{{ kolla_internal_fqdn_cert }}"
+        mode: "0660"
+  when:
+    - kolla_enable_tls_internal | bool
+    - not kolla_same_external_internal_vip | bool
diff --git a/ansible/roles/certificates/templates/openssl-kolla-internal.cnf.j2 b/ansible/roles/certificates/templates/openssl-kolla-internal.cnf.j2
new file mode 100644
index 0000000000..0fc84f2bd4
--- /dev/null
+++ b/ansible/roles/certificates/templates/openssl-kolla-internal.cnf.j2
@@ -0,0 +1,21 @@
+[req]
+prompt = no
+distinguished_name = req_distinguished_name
+req_extensions = v3_req
+
+[req_distinguished_name]
+countryName = US
+stateOrProvinceName = NC
+localityName = RTP
+organizationalUnitName = kolla
+commonName = {{ kolla_internal_fqdn }}
+
+[v3_req]
+subjectAltName = @alt_names
+
+[alt_names]
+{% if kolla_internal_fqdn != kolla_internal_vip_address %}
+DNS.1 = {{ kolla_internal_fqdn }}
+{% else %}
+IP.1 = {{ kolla_internal_fqdn }}
+{% endif %}
diff --git a/ansible/roles/certificates/templates/openssl-kolla.cnf.j2 b/ansible/roles/certificates/templates/openssl-kolla.cnf.j2
index 4e15b92b82..a0273720dd 100644
--- a/ansible/roles/certificates/templates/openssl-kolla.cnf.j2
+++ b/ansible/roles/certificates/templates/openssl-kolla.cnf.j2
@@ -1,4 +1,5 @@
 [req]
+prompt = no
 distinguished_name = req_distinguished_name
 req_extensions = v3_req
 
diff --git a/doc/source/admin/advanced-configuration.rst b/doc/source/admin/advanced-configuration.rst
index 9d5b52ed20..765ed2f69b 100644
--- a/doc/source/admin/advanced-configuration.rst
+++ b/doc/source/admin/advanced-configuration.rst
@@ -140,7 +140,7 @@ have settings similar to this:
    export OS_PASSWORD=demo-password
    export OS_AUTH_URL=https://mykolla.example.net:5000
    # os_cacert is optional for trusted certificates
-   export OS_CACERT=/etc/pki/mykolla-cacert.crt
+   export OS_CACERT=/etc/pki/ca/mykolla-cacert.crt
    export OS_IDENTITY_API_VERSION=3
 
 Self-Signed Certificates
@@ -162,8 +162,9 @@ configuration file:
 
    kolla-ansible certificates
 
-The files haproxy.pem and haproxy-ca.pem will be generated and stored
-in the ``/etc/kolla/certificates/`` directory.
+The certificate file haproxy.pem will be generated and stored in the
+``/etc/kolla/certificates/`` directory, and the CA cert will be in the
+``/etc/kolla/certificates/ca/`` directory.
 
 Adding CA Certificates to the Service Containers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index e661910b19..807f6581ef 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -184,8 +184,8 @@
 #kolla_enable_tls_external: "{{ kolla_enable_tls_internal if kolla_same_external_internal_vip | bool else 'no' }}"
 #kolla_external_fqdn_cert: "{{ node_config }}/certificates/haproxy.pem"
 #kolla_internal_fqdn_cert: "{{ node_config }}/certificates/haproxy-internal.pem"
-#kolla_external_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca.crt"
-#kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/haproxy-ca-internal.crt"
+#kolla_external_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy.crt"
+#kolla_internal_fqdn_cacert: "{{ node_config }}/certificates/ca/haproxy-internal.crt"
 #kolla_copy_ca_into_containers: "no"
 
 ################
diff --git a/releasenotes/notes/generate-internal-external-self-signed-certs-c631a9d934d31fac.yaml b/releasenotes/notes/generate-internal-external-self-signed-certs-c631a9d934d31fac.yaml
new file mode 100644
index 0000000000..94ea0638e5
--- /dev/null
+++ b/releasenotes/notes/generate-internal-external-self-signed-certs-c631a9d934d31fac.yaml
@@ -0,0 +1,23 @@
+---
+features:
+  - |
+    Generate self signed certificates for both the internal and external
+    (public) networks. If they are the same network, then the certificate
+    files will be the same.
+upgrade:
+  - |
+    The default value for ``kolla_external_fqdn_cacert`` has been changed
+    from:
+    "{{ node_config }}/certificates/haproxy-ca.crt"
+    to:
+    "{{ node_config }}/certificates/ca/haproxy.crt"
+
+    and the default value for ``kolla_external_fqdn_cacert`` has been changed
+    from:
+    "{{ node_config }}/certificates/haproxy-ca-internal.crt"
+    to:
+    "{{ node_config }}/certificates/ca/haproxy-internal.crt"
+
+    These variables set the value for the ``OS_CACERT`` environment variable in
+    ``admin-openrc.sh``. This has been done to allow these certificates to be
+    copied into containers when ``kolla_copy_ca_into_containers`` is true.