diff --git a/docker/services/haproxy.yaml b/docker/services/haproxy.yaml index 88bd2be1ec..b44856687f 100644 --- a/docker/services/haproxy.yaml +++ b/docker/services/haproxy.yaml @@ -256,6 +256,7 @@ outputs: environment: - KOLLA_CONFIG_STRATEGY=COPY_ALWAYS host_prep_tasks: + - {get_attr: [HAProxyBase, role_data, host_prep_tasks]} - name: create persistent directories file: path: "{{ item }}" diff --git a/docker/services/pacemaker/haproxy.yaml b/docker/services/pacemaker/haproxy.yaml index 9e2259899b..ff9cb572e3 100644 --- a/docker/services/pacemaker/haproxy.yaml +++ b/docker/services/pacemaker/haproxy.yaml @@ -246,6 +246,7 @@ outputs: - /etc/corosync/corosync.conf:/etc/corosync/corosync.conf:ro - /dev/shm:/dev/shm:rw host_prep_tasks: + - {get_attr: [HAProxyBase, role_data, host_prep_tasks]} - name: create persistent directories file: path: "{{ item }}" diff --git a/environments/enable-tls.yaml b/environments/enable-tls.yaml index 7d3796e7ca..968f8980a2 100644 --- a/environments/enable-tls.yaml +++ b/environments/enable-tls.yaml @@ -16,4 +16,4 @@ parameter_defaults: GnocchiIncomingStorageDriver: '' resource_registry: - OS::TripleO::NodeTLSData: ../puppet/extraconfig/tls/tls-cert-inject.yaml + OS::TripleO::NodeTLSData: OS::Heat::None diff --git a/environments/ssl/enable-tls.yaml b/environments/ssl/enable-tls.yaml index f3c5bf034c..df1294cc49 100644 --- a/environments/ssl/enable-tls.yaml +++ b/environments/ssl/enable-tls.yaml @@ -7,8 +7,8 @@ # title: Enable SSL on OpenStack Public Endpoints # description: | # Use this environment to pass in certificates for SSL deployments. -# For these values to take effect, one of the tls-endpoints-*.yaml environments -# must also be used. +# For these values to take effect, one of the tls-endpoints-*.yaml +# environments must also be used. parameter_defaults: # The content of the SSL certificate (without Key) in PEM format. # Type: string @@ -35,5 +35,3 @@ parameter_defaults: # ********************* # End static parameters # ********************* -resource_registry: - OS::TripleO::NodeTLSData: ../../puppet/extraconfig/tls/tls-cert-inject.yaml diff --git a/overcloud-resource-registry-puppet.j2.yaml b/overcloud-resource-registry-puppet.j2.yaml index 178cecbe36..746124c28a 100644 --- a/overcloud-resource-registry-puppet.j2.yaml +++ b/overcloud-resource-registry-puppet.j2.yaml @@ -55,7 +55,7 @@ resource_registry: OS::TripleO::{{role.name}}::NodeUserData: firstboot/userdata_default.yaml {% endfor %} OS::TripleO::NodeTLSCAData: OS::Heat::None - OS::TripleO::NodeTLSData: puppet/extraconfig/tls/tls-cert-inject.yaml + OS::TripleO::NodeTLSData: OS::Heat::None OS::TripleO::NodeExtraConfig: puppet/extraconfig/pre_deploy/default.yaml OS::TripleO::NodeExtraConfigPost: extraconfig/post_deploy/default.yaml @@ -177,7 +177,7 @@ resource_registry: OS::TripleO::Services::RabbitMQ: OS::Heat::None OS::TripleO::Services::Qdr: OS::Heat::None OS::TripleO::Services::HAproxy: docker/services/haproxy.yaml - OS::TripleO::Services::HAProxyPublicTLS: OS::Heat::None + OS::TripleO::Services::HAProxyPublicTLS: puppet/services/haproxy-public-tls-inject.yaml OS::TripleO::Services::HAProxyInternalTLS: OS::Heat::None OS::TripleO::Services::Iscsid: docker/services/iscsid.yaml OS::TripleO::Services::Keepalived: docker/services/keepalived.yaml diff --git a/puppet/role.role.j2.yaml b/puppet/role.role.j2.yaml index 8934ab73c1..072f7ae68a 100644 --- a/puppet/role.role.j2.yaml +++ b/puppet/role.role.j2.yaml @@ -562,16 +562,6 @@ resources: properties: server: {get_resource: {{server_resource_name}}} - {%- if 'primary' in role.tags and 'controller' in role.tags %} - # Resource for site-specific passing of private keys/certificates - NodeTLSData: - depends_on: NodeTLSCAData - type: OS::TripleO::NodeTLSData - properties: - server: {get_resource: {{server_resource_name}}} - NodeIndex: {get_param: NodeIndex} - {%- endif -%} - # Hook for site-specific additional pre-deployment config, e.g extra hieradata {{role.name}}ExtraConfigPre: depends_on: {{server_resource_name}}Deployment @@ -587,11 +577,7 @@ resources: NodeExtraConfig: depends_on: - {{role.name}}ExtraConfigPre - {%- if 'primary' in role.tags and 'controller' in role.tags %} - - NodeTLSData - {%- else %} - NodeTLSCAData - {%- endif %} type: OS::TripleO::NodeExtraConfig # We have to use conditions here so that we don't break backwards # compatibility with templates everywhere @@ -742,14 +728,6 @@ outputs: - 6 - 0 - keys: {hostname: {get_param: Hostname}} - {%- if 'primary' in role.tags and 'controller' in role.tags %} - tls_key_modulus_md5: - description: MD5 checksum of the TLS Key Modulus - value: {get_attr: [NodeTLSData, key_modulus_md5]} - tls_cert_modulus_md5: - description: MD5 checksum of the TLS Certificate Modulus - value: {get_attr: [NodeTLSData, cert_modulus_md5]} - {%- endif %} os_collect_config: description: The os-collect-config configuration associated with this server resource value: {get_attr: [{{server_resource_name}}, os_collect_config]} diff --git a/puppet/services/haproxy-public-tls-inject.yaml b/puppet/services/haproxy-public-tls-inject.yaml new file mode 100644 index 0000000000..ff2b6bc49f --- /dev/null +++ b/puppet/services/haproxy-public-tls-inject.yaml @@ -0,0 +1,190 @@ +heat_template_version: rocky + +description: > + HAProxy deployment with TLS enabled, with an injected certificate + +parameters: + ServiceData: + default: {} + description: Dictionary packing service data + type: json + ServiceNetMap: + default: {} + description: Mapping of service_name -> network name. Typically set + via parameter_defaults in the resource registry. This + mapping overrides those in ServiceNetMapDefaults. + type: json + DefaultPasswords: + default: {} + type: json + RoleName: + default: '' + description: Role name on which the service is applied + type: string + RoleParameters: + default: {} + description: Parameters specific to the role + type: json + EndpointMap: + default: {} + description: Mapping of service endpoint -> protocol. Typically set + via parameter_defaults in the resource registry. + type: json + # Can be overridden via parameter_defaults in the environment + SSLCertificate: + default: '' + description: > + The content of the SSL certificate (without Key) in PEM format. + type: string + SSLIntermediateCertificate: + default: '' + description: > + The content of an SSL intermediate CA certificate in PEM format. + type: string + # NOTE(jaosorior): Adding this default is only while we enable TLS by default + # for the overcloud. It'll be removed in a subsequent patch. + SSLKey: + default: '' + description: > + The content of the SSL Key in PEM format. + type: string + hidden: true + DeployedSSLCertificatePath: + default: '/etc/pki/tls/private/overcloud_endpoint.pem' + description: > + The filepath of the certificate as it will be stored in the controller. + type: string + +outputs: + role_data: + description: Role data for the HAProxy public TLS injection. + value: + service_name: haproxy_public_tls_inject + config_settings: {} + certificates_specs: {} + metadata_settings: null + host_prep_tasks: + - name: get parameters + set_fact: + cert_path: {get_param: DeployedSSLCertificatePath} + cert_content: {get_param: SSLCertificate} + chain_content: {get_param: SSLIntermediateCertificate} + key_content: {get_param: SSLKey} + no_log: true + + # We want to ensure we run all this block IFF we have + # a certificate content. + - name: manage certificate + when: + - cert_content is defined + - cert_content != '' + block: + - name: get DeployedSSLCertificatePath attributes + register: attr_cert_path + stat: + path: "{{cert_path}}" + + - name: Assign bootstrap node + command: hiera -c /etc/puppet/hiera.yaml bootstrap_nodeid + register: bootstrap_node + + - name: set is_bootstrap_node fact + set_fact: is_bootstrap_node={{bootstrap_node.stdout|lower == ansible_hostname|lower}} + + - name: get haproxy status + register: haproxy_state + systemd: + name: haproxy + + - name: get pacemaker status + register: pacemaker_state + systemd: + name: pacemaker + + - name: get docker status + register: docker_state + systemd: + name: docker + + - name: get container_id + when: + - docker_state.status.ActiveState == 'active' + - attr_cert_path.stat.exists + - attr_cert_path.stat.isdir == False + command: docker ps -q -f name=haproxy + register: container_id + + - name: get pcs resource name for haproxy container + when: + - bootstrap_node is defined + - is_bootstrap_node + - pacemaker_state.status.ActiveState == 'active' + - attr_cert_path.stat.exists + - attr_cert_path.stat.isdir + shell: | + pcs status resources | sed -n 's/^.*container.*: \(haproxy.*\) .*/\1/p' + register: pacemaker_resource + + # It might happen docker has started priori the file creation - it will then create a + # directory. We have to drop that directory in order to push our file. + - name: remove DeployedSSLCertificatePath if is dir + when: attr_cert_path.stat.isdir is defined and attr_cert_path.stat.isdir + file: + path: "{{cert_path}}" + state: absent + + # In containerized env, haproxy group does not exist. + # We hence need to do this file creation in two distinct steps + # and ignore failure on the ownership change. + - name: push certificate content + no_log: true + copy: + dest: "{{cert_path}}" + mode: 0440 + owner: root + content: | + {{cert_content}} + {{chain_content}} + {{key_content}} + + # Set certificate group IFF we're not in container context + # Also, restart HAProxy service without more concern + - name: BM haproxy non-pacemaker context + when: haproxy_state.status.ActiveState == 'active' + block: + - name: set certificate ownership + file: + path: "{{cert_path}}" + group: haproxy + + - name: reload haproxy if enabled + service: + name: haproxy + state: reloaded + + - name: restart pacemaker resource for haproxy + when: + - pacemaker_resource is defined + - pacemaker_resource.stdout is defined + - pacemaker_resource.stdout != '' + command: pcs resource restart "{{pacemaker_resource.stdout}}" + + # We can't use kolla for certificate updates, so we have to + # set its rights and restart the service. + - name: dedicated part for containers + when: + - container_id is defined + - container_id.stdout is defined + - container_id.stdout != '' + block: + - name: set kolla_dir fact + set_fact: kolla_dir="/var/lib/kolla/config_files/src-tls" + + - name: set certificate group on host via container + command: docker exec {{container_id.stdout}} chgrp haproxy {{kolla_dir}}{{cert_path}} + + - name: copy certificate from kolla directory to final location + command: docker exec {{container_id.stdout}} cp {{kolla_dir}}{{cert_path}} {{cert_path}} + + - name: send restart order to haproxy container + command: docker kill --signal=HUP {{container_id.stdout}} diff --git a/puppet/services/haproxy.yaml b/puppet/services/haproxy.yaml index 709bda918d..6f8bdb386e 100644 --- a/puppet/services/haproxy.yaml +++ b/puppet/services/haproxy.yaml @@ -177,6 +177,7 @@ outputs: - step|int == 4 - haproxy_enabled.rc == 0 service: name=haproxy state=started + host_prep_tasks: {get_attr: [HAProxyPublicTLS, role_data, host_prep_tasks]} metadata_settings: list_concat: - {get_attr: [HAProxyPublicTLS, role_data, metadata_settings]} diff --git a/puppet/services/pacemaker/haproxy.yaml b/puppet/services/pacemaker/haproxy.yaml index 76c154b553..b91e570b56 100644 --- a/puppet/services/pacemaker/haproxy.yaml +++ b/puppet/services/pacemaker/haproxy.yaml @@ -55,5 +55,6 @@ outputs: tripleo::haproxy::mysql_clustercheck: true step_config: | include ::tripleo::profile::pacemaker::haproxy + host_prep_tasks: {get_attr: [LoadbalancerServiceBase, role_data, host_prep_tasks]} metadata_settings: get_attr: [LoadbalancerServiceBase, role_data, metadata_settings] diff --git a/releasenotes/notes/tls-inject-86ef6706e68f5740.yaml b/releasenotes/notes/tls-inject-86ef6706e68f5740.yaml new file mode 100644 index 0000000000..00d2467fc1 --- /dev/null +++ b/releasenotes/notes/tls-inject-86ef6706e68f5740.yaml @@ -0,0 +1,13 @@ +--- +prelude: > + TLS certificate injection is now done with Ansible instead of a bash + script called by Heat. + + It deprecates the NodeTLSData resource and script, while keeping the use of + its variables (SSLCertificate, SSLIntermediateCertificate, SSLKey) +upgrade: + - All NodeTLSData related resources must be removed. + - SSLCertificate, SSLIntermediateCertificate, SSLKey are still used for the + TLS configuration. +deprecations: + - NodeTLSData is now deprecated. diff --git a/sample-env-generator/ssl.yaml b/sample-env-generator/ssl.yaml index c1ef36b64d..eec3b1b04f 100644 --- a/sample-env-generator/ssl.yaml +++ b/sample-env-generator/ssl.yaml @@ -4,10 +4,10 @@ environments: title: Enable SSL on OpenStack Public Endpoints description: | Use this environment to pass in certificates for SSL deployments. - For these values to take effect, one of the tls-endpoints-*.yaml environments - must also be used. + For these values to take effect, one of the tls-endpoints-*.yaml + environments must also be used. files: - puppet/extraconfig/tls/tls-cert-inject.yaml: + puppet/services/haproxy-public-tls-inject.yaml: parameters: all static: # This should probably be private, but for testing static params I'm @@ -20,8 +20,6 @@ environments: SSLKey: |- | The contents of the private key go here - resource_registry: - OS::TripleO::NodeTLSData: ../../puppet/extraconfig/tls/tls-cert-inject.yaml - name: ssl/enable-internal-tls title: Enable SSL on OpenStack Internal Endpoints