diff --git a/defaults/main.yml b/defaults/main.yml index ee4181b..24ae8eb 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -22,11 +22,106 @@ zookeeper_download_url: "https://dlcdn.apache.org/zookeeper/zookeeper-{{ zookeep zookeeper_cluster_members: "{{ groups['zookeeper_all'] }}" # The fist port is used by followers to connect to the leader # The second one is used for leader election -zookeeper_cluster_peer_ports: 2888:3888 # This variable is used to define what fact which will be taken out of # hostvars for each cluster member as it's address zookeeper_cluster_address_hostvars_key: "ansible_host" + +# Ports and TLS +zookeeper_cluster_peer_ports: 2888:3888 zookeeper_client_port: 2181 +zookeeper_secure_client_port: 2281 +zookeeper_ssl_client_enable: True +zookeeper_ssl_quorum_enable: True +zookeeper_ssl_protocols: + - TLSv1.2 + - TLSv1.3 + +# Storage location for SSL certificate authority +zookeeper_pki_dir: "{{ openstack_pki_dir | default('/etc/pki/zookeeper-ca') }}" + +# Delegated host for operating the certificate authority +zookeeper_pki_setup_host: "{{ openstack_pki_setup_host | default('localhost') }}" + +# Create a certificate authority if one does not already exist +zookeeper_pki_create_ca: "{{ openstack_pki_authorities is not defined | bool }}" +zookeeper_pki_regen_ca: '' +zookeeper_pki_authorities: + - name: "ZookeeperRoot" + country: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + cn: "Zookeeper Root CA" + provider: selfsigned + basic_constraints: "CA:TRUE" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + - name: "ZookeeperIntermediate" + country: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + cn: "Zookeeper Intermediate CA" + provider: ownca + basic_constraints: "CA:TRUE,pathlen:0" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + signed_by: "ZookeeperRoot" + +# Installation details for certificate authorities +zookeeper_pki_install_ca: + - name: "ZookeeperRoot" + condition: "{{ zookeeper_pki_create_ca }}" + +# Zookeeper server certificate +zookeeper_pki_keys_path: "{{ zookeeper_pki_dir ~ '/certs/private/' }}" +zookeeper_pki_certs_path: "{{ zookeeper_pki_dir ~ '/certs/certs/' }}" +zookeeper_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('ZookeeperIntermediate') }}" +zookeeper_pki_intermediate_cert_path: "{{ zookeeper_pki_dir ~ '/roots/' ~ zookeeper_pki_intermediate_cert_name ~ '/certs/' ~ zookeeper_pki_intermediate_cert_name ~ '.crt' }}" +zookeeper_pki_regen_cert: '' +zookeeper_pki_certificates: + - name: "zookeeper_{{ ansible_facts['hostname'] }}" + provider: ownca + cn: "{{ hostvars[inventory_hostname][zookeeper_cluster_address_hostvars_key] }}" + san: "{{ 'DNS:' ~ ansible_facts['fqdn'] ~ ',IP:' ~ ansible_host }}" + signed_by: "{{ zookeeper_pki_intermediate_cert_name }}" + condition: "{{ zookeeper_ssl_client_enable or zookeeper_ssl_quorum_enable }}" + key_format: pkcs8 + +# Installation details for SSL certificates +zookeeper_pki_install_certificates: + - src: "{{ zookeeper_user_ssl_cert | default(zookeeper_pki_certs_path ~ 'zookeeper_' ~ ansible_facts['hostname'] ~ '.crt') }}" + dest: "{{ zookeeper_ssl_cert }}" + owner: "{{ zookeeper_system_user_name }}" + group: "{{ zookeeper_system_group_name }}" + mode: "0644" + condition: "{{ zookeeper_ssl_client_enable or zookeeper_ssl_quorum_enable }}" + - src: "{{ zookeeper_user_ssl_key | default(zookeeper_pki_keys_path ~ 'zookeeper_' ~ ansible_facts['hostname'] ~ '.key.pem') }}" + dest: "{{ zookeeper_ssl_key }}" + owner: "{{ zookeeper_system_user_name }}" + group: "{{ zookeeper_system_group_name }}" + mode: "0600" + condition: "{{ zookeeper_ssl_client_enable or zookeeper_ssl_quorum_enable }}" + - src: "{{ zookeeper_user_ssl_ca_cert | default(zookeeper_pki_intermediate_cert_path) }}" + dest: "{{ zookeeper_ssl_ca_cert }}" + owner: "{{ zookeeper_system_user_name }}" + group: "{{ zookeeper_system_group_name }}" + mode: "0644" + condition: "{{ zookeeper_ssl_client_enable or zookeeper_ssl_quorum_enable }}" + +zookeeper_ssl_cert: "{{ zookeeper_config_dir }}/certs/certs/zookeeper.crt" +zookeeper_ssl_key: "{{ zookeeper_config_dir }}/certs/private/zookeeper.key" +zookeeper_ssl_ca_cert: "{{ zookeeper_config_dir }}/certs/certs/zookeeper-ca.crt" +zookeeper_ssl_keystore_location: "{{ zookeeper_config_dir }}/certs/private/zookeeper.pem" +zookeeper_ssl_truststore_location: "{{ _zookeeper_ssl_truststore_location }}" +zookeeper_ssl_client_auth: want +zookeeper_ssl_quorum_client_auth: need # Define operating system user/group names zookeeper_system_user_name: zookeeper diff --git a/handlers/main.yml b/handlers/main.yml index 40fd5bf..a396d62 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -13,6 +13,13 @@ # License for the specific language governing permissions and limitations # under the License. +- name: regen pem + shell: > + cat {{ zookeeper_ssl_cert }} $(test -f {{ zookeeper_ssl_ca_cert }} && echo {{ zookeeper_ssl_ca_cert }}) {{ zookeeper_ssl_key }} > {{ zookeeper_ssl_keystore_location }} + notify: Restart zookeeper + listen: + - cert installed + - name: Stop zookeeper service: name: "{{ zookeeper_service['name'] }}" diff --git a/tasks/main.yml b/tasks/main.yml index ae44f70..05d3429 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -40,6 +40,23 @@ tags: - zookeeper-config +- name: Create and install SSL certificates + include_role: + name: pki + vars: + pki_setup_host: "{{ zookeeper_pki_setup_host }}" + pki_dir: "{{ zookeeper_pki_dir }}" + pki_create_ca: "{{ zookeeper_pki_create_ca }}" + pki_authorities: "{{ zookeeper_pki_authorities }}" + pki_install_ca: "{{ zookeeper_pki_install_ca }}" + pki_regen_ca: "{{ zookeeper_pki_regen_ca }}" + pki_create_certificates: "{{ zookeeper_user_ssl_cert is not defined and zookeeper_user_ssl_key is not defined }}" + pki_regen_cert: "{{ zookeeper_pki_regen_cert }}" + pki_certificates: "{{ zookeeper_pki_certificates }}" + pki_install_certificates: "{{ zookeeper_pki_install_certificates }}" + when: + - zookeeper_ssl_client_enable or zookeeper_ssl_quorum_enable + - name: Run the systemd service role include_role: name: systemd_service diff --git a/templates/zoo.cfg.j2 b/templates/zoo.cfg.j2 index e09afee..9151d3a 100644 --- a/templates/zoo.cfg.j2 +++ b/templates/zoo.cfg.j2 @@ -34,3 +34,25 @@ autopurge.snapRetainCount={{ zookeeper_snap_retain_count }} autopurge.purgeInterval={{ zookeeper_purge_interval }} 4lw.commands.whitelist={{ zookeeper_commands_whitelist | join(', ') }} + +{% if zookeeper_ssl_client_enable | bool or zookeeper_ssl_quorum_enable | bool %} +serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory +{% endif %} + +{% if zookeeper_ssl_client_enable | bool %} +secureClientPort={{ zookeeper_secure_client_port }} +ssl.keyStore.location={{ zookeeper_ssl_keystore_location }} +ssl.trustStore.location={{ zookeeper_ssl_truststore_location }} +ssl.enabledProtocols={{ zookeeper_ssl_protocols | join(',') }} +ssl.trustStore.type=PEM +ssl.clientAuth={{ zookeeper_ssl_client_auth }} +{% endif %} + +{% if zookeeper_ssl_quorum_enable | bool %} +sslQuorum=true +ssl.quorum.keyStore.location={{ zookeeper_ssl_keystore_location }} +ssl.quorum.trustStore.location={{ zookeeper_ssl_truststore_location }} +ssl.quorum.enabledProtocols={{ zookeeper_ssl_protocols | join(',') }} +ssl.quorum.trustStore.type=PEM +ssl.quorum.clientAuth={{ zookeeper_ssl_quorum_client_auth }} +{% endif %} diff --git a/vars/debian.yml b/vars/debian.yml index acd9cce..2a64b0e 100644 --- a/vars/debian.yml +++ b/vars/debian.yml @@ -17,3 +17,5 @@ _zookeeper_package_requirements: - openjdk-11-jre-headless - tar - gzip + +_zookeeper_ssl_truststore_location: /etc/ssl/certs/ca-certificates.crt diff --git a/vars/redhat.yml b/vars/redhat.yml index 1655806..f26f2b8 100644 --- a/vars/redhat.yml +++ b/vars/redhat.yml @@ -17,3 +17,5 @@ _zookeeper_package_requirements: - java-11-openjdk-headless - tar - gzip + +_zookeeper_ssl_truststore_location: /etc/pki/tls/certs/ca-bundle.crt