Browse Source

Manage public certificate with ansible

This is basically a rewrite of the bash script pushed by
puppet/extraconfig/tls/tls-cert-inject.yaml

UpgradeImpact: NodeTLSData is not used anymore

Change-Id: Iaf7386207e5bd8b336759f51e4405fe15114123a
changes/27/570627/23
Cédric Jeanneret 4 years ago
parent
commit
59b762658d
  1. 1
      docker/services/haproxy.yaml
  2. 1
      docker/services/pacemaker/haproxy.yaml
  3. 2
      environments/enable-tls.yaml
  4. 6
      environments/ssl/enable-tls.yaml
  5. 4
      overcloud-resource-registry-puppet.j2.yaml
  6. 22
      puppet/role.role.j2.yaml
  7. 190
      puppet/services/haproxy-public-tls-inject.yaml
  8. 1
      puppet/services/haproxy.yaml
  9. 1
      puppet/services/pacemaker/haproxy.yaml
  10. 13
      releasenotes/notes/tls-inject-86ef6706e68f5740.yaml
  11. 8
      sample-env-generator/ssl.yaml

1
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 }}"

1
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 }}"

2
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

6
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

4
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

22
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]}

190
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}}

1
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]}

1
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]

13
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.

8
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

Loading…
Cancel
Save