From 68409bc81f9cd1b87b546b767018dabe9ccfd59e Mon Sep 17 00:00:00 2001 From: Tristan Cacqueray <tdecacqu@redhat.com> Date: Wed, 17 Feb 2021 23:01:00 +0000 Subject: [PATCH] ensure-zookeeper: add use_tls role var This change adds a new attribute to setup zookeeper TLS. It also adds support for Debian-derived distros. Change-Id: Ifb5fc51f3b66be0b2dd1b8003507e21d8afe16fc --- roles/ensure-zookeeper/README.rst | 5 + roles/ensure-zookeeper/defaults/main.yaml | 3 + roles/ensure-zookeeper/files/openssl.cnf | 352 ++++++++++++++++++++ roles/ensure-zookeeper/files/zk-ca.sh | 104 ++++++ roles/ensure-zookeeper/tasks/Debian.yaml | 5 + roles/ensure-zookeeper/tasks/RedHat.yaml | 5 + roles/ensure-zookeeper/tasks/default.yaml | 5 + roles/ensure-zookeeper/tasks/main.yaml | 17 +- roles/ensure-zookeeper/tasks/setup_tls.yaml | 37 ++ test-playbooks/ensure-zookeeper.yaml | 2 + 10 files changed, 530 insertions(+), 5 deletions(-) create mode 100644 roles/ensure-zookeeper/files/openssl.cnf create mode 100755 roles/ensure-zookeeper/files/zk-ca.sh create mode 100644 roles/ensure-zookeeper/tasks/Debian.yaml create mode 100644 roles/ensure-zookeeper/tasks/RedHat.yaml create mode 100644 roles/ensure-zookeeper/tasks/default.yaml create mode 100644 roles/ensure-zookeeper/tasks/setup_tls.yaml diff --git a/roles/ensure-zookeeper/README.rst b/roles/ensure-zookeeper/README.rst index 6cb380725..882bc5d55 100644 --- a/roles/ensure-zookeeper/README.rst +++ b/roles/ensure-zookeeper/README.rst @@ -8,3 +8,8 @@ Install and start zookeeper using the upsteam release. :default: latest The zookeeper version. + +.. zuul:rolevar:: zookeeper_use_tls + :default: false + + Setup zookeeper tls certificates. diff --git a/roles/ensure-zookeeper/defaults/main.yaml b/roles/ensure-zookeeper/defaults/main.yaml index f22379d63..f8c117113 100644 --- a/roles/ensure-zookeeper/defaults/main.yaml +++ b/roles/ensure-zookeeper/defaults/main.yaml @@ -1,3 +1,6 @@ zookeeper_version: "latest" _zookeeper_latest_version: "3.6.1" _zookeeper_install_version: "{% if zookeeper_version == 'latest' %}{{ _zookeeper_latest_version }}{% else %}{{ zookeeper_version }}{% endif %}" + +zookeeper_use_tls: false +zookeeper_ca_dir: "/opt/zookeeper/ca" diff --git a/roles/ensure-zookeeper/files/openssl.cnf b/roles/ensure-zookeeper/files/openssl.cnf new file mode 100644 index 000000000..7d1a8bb6e --- /dev/null +++ b/roles/ensure-zookeeper/files/openssl.cnf @@ -0,0 +1,352 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# Note that you can include other files from the main configuration +# file using the .include directive. +#.include filename + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certs with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extensions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +basicConstraints = critical,CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) +signer_digest = sha256 # Signing digest to use. (Optional) +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) +ess_cert_id_alg = sha1 # algorithm to compute certificate + # identifier (optional, default: sha1) diff --git a/roles/ensure-zookeeper/files/zk-ca.sh b/roles/ensure-zookeeper/files/zk-ca.sh new file mode 100755 index 000000000..4cd72cac6 --- /dev/null +++ b/roles/ensure-zookeeper/files/zk-ca.sh @@ -0,0 +1,104 @@ +#!/bin/sh -e + +# Copyright 2020 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Manage a CA for Zookeeper + +CAROOT=$1 +SERVER=$2 + +SUBJECT='/C=US/ST=California/L=Oakland/O=Company Name/OU=Org' +TOOLSDIR=$(dirname $0) +ABSTOOLSDIR=$(cd $TOOLSDIR ;pwd) +CONFIG="-config $ABSTOOLSDIR/openssl.cnf" + +make_ca() { + mkdir $CAROOT/demoCA + mkdir $CAROOT/demoCA/reqs + mkdir $CAROOT/demoCA/newcerts + mkdir $CAROOT/demoCA/crl + mkdir $CAROOT/demoCA/private + chmod 700 $CAROOT/demoCA/private + touch $CAROOT/demoCA/index.txt + touch $CAROOT/demoCA/index.txt.attr + mkdir $CAROOT/certs + mkdir $CAROOT/keys + mkdir $CAROOT/keystores + chmod 700 $CAROOT/keys + chmod 700 $CAROOT/keystores + + openssl req $CONFIG -new -nodes -subj "$SUBJECT/CN=caroot" \ + -keyout $CAROOT/demoCA/private/cakey.pem \ + -out $CAROOT/demoCA/reqs/careq.pem + openssl ca $CONFIG -create_serial -days 3560 -batch -selfsign -extensions v3_ca \ + -out $CAROOT/demoCA/cacert.pem \ + -keyfile $CAROOT/demoCA/private/cakey.pem \ + -infiles $CAROOT/demoCA/reqs/careq.pem + cp $CAROOT/demoCA/cacert.pem $CAROOT/certs +} + +make_client() { + openssl req $CONFIG -new -nodes -subj "$SUBJECT/CN=client" \ + -keyout $CAROOT/keys/clientkey.pem \ + -out $CAROOT/demoCA/reqs/clientreq.pem + openssl ca $CONFIG -batch -policy policy_anything -days 3560 \ + -out $CAROOT/certs/client.pem \ + -infiles $CAROOT/demoCA/reqs/clientreq.pem +} + +make_server() { + openssl req $CONFIG -new -nodes -subj "$SUBJECT/CN=$SERVER" \ + -keyout $CAROOT/keys/${SERVER}key.pem \ + -out $CAROOT/demoCA/reqs/${SERVER}req.pem + openssl ca $CONFIG -batch -policy policy_anything -days 3560 \ + -out $CAROOT/certs/$SERVER.pem \ + -infiles $CAROOT/demoCA/reqs/${SERVER}req.pem + cat $CAROOT/certs/$SERVER.pem $CAROOT/keys/${SERVER}key.pem \ + > $CAROOT/keystores/$SERVER.pem +} + +help() { + echo "$0 CAROOT [SERVER]" + echo + echo " CAROOT is the path to a directory in which to store the CA" + echo " and certificates." + echo " SERVER is the FQDN of a server for which a certificate should" + echo " be generated" +} + +if [ ! -d "$CAROOT" ]; then + echo "CAROOT must be a directory" + help + exit 1 +fi + +cd $CAROOT +CAROOT=`pwd` + +if [ ! -d "$CAROOT/demoCA" ]; then + echo 'Generate CA' + make_ca + echo 'Generate client certificate' + make_client +fi + +if [ -f "$CAROOT/certs/$SERVER.pem" ]; then + echo "Certificate for $SERVER already exists" + exit 0 +fi + +if [ "$SERVER" != "" ]; then + make_server +fi diff --git a/roles/ensure-zookeeper/tasks/Debian.yaml b/roles/ensure-zookeeper/tasks/Debian.yaml new file mode 100644 index 000000000..feb16ea90 --- /dev/null +++ b/roles/ensure-zookeeper/tasks/Debian.yaml @@ -0,0 +1,5 @@ +- name: Install JDK + package: + name: default-jdk-headless + state: present + become: true diff --git a/roles/ensure-zookeeper/tasks/RedHat.yaml b/roles/ensure-zookeeper/tasks/RedHat.yaml new file mode 100644 index 000000000..3fa2c7897 --- /dev/null +++ b/roles/ensure-zookeeper/tasks/RedHat.yaml @@ -0,0 +1,5 @@ +- name: Install JDK + package: + name: java-latest-openjdk + state: present + become: true diff --git a/roles/ensure-zookeeper/tasks/default.yaml b/roles/ensure-zookeeper/tasks/default.yaml new file mode 100644 index 000000000..eeedd9348 --- /dev/null +++ b/roles/ensure-zookeeper/tasks/default.yaml @@ -0,0 +1,5 @@ +- name: Warn about unsupported distribution + debug: + msg: > + WARNING: Installation of Java on {{ ansible_distribution }} is not + supported by this role yet. diff --git a/roles/ensure-zookeeper/tasks/main.yaml b/roles/ensure-zookeeper/tasks/main.yaml index 692b68097..6ea2e9fda 100644 --- a/roles/ensure-zookeeper/tasks/main.yaml +++ b/roles/ensure-zookeeper/tasks/main.yaml @@ -1,8 +1,11 @@ -- name: Install JDK - package: - name: java-latest-openjdk - state: present - become: true +- name: Install distro-specific packages + include_tasks: "{{ zj_distro_os }}" + with_first_found: + - "{{ ansible_distribution }}.yaml" + - "{{ ansible_os_family }}.yaml" + - "default.yaml" + loop_control: + loop_var: zj_distro_os - name: Create /tmp/zookeeper file: @@ -33,6 +36,10 @@ mode: 0644 become: true +- name: Setup ZooKeeper TLS + include_tasks: ./setup_tls.yaml + when: zookeeper_use_tls + - name: Ensure Zookeeper not running command: pkill -f zookeeper ignore_errors: true diff --git a/roles/ensure-zookeeper/tasks/setup_tls.yaml b/roles/ensure-zookeeper/tasks/setup_tls.yaml new file mode 100644 index 000000000..791bef158 --- /dev/null +++ b/roles/ensure-zookeeper/tasks/setup_tls.yaml @@ -0,0 +1,37 @@ +- name: Instal openssl + package: + name: openssl + become: true + +- name: Ensure CA dir is created + file: + path: "{{ zookeeper_ca_dir }}" + state: directory + owner: "{{ ansible_user }}" + become: true + +- name: Copy zk-ca script + copy: + src: zk-ca.sh + dest: "{{ zookeeper_ca_dir }}/zk-ca.sh" + mode: 0755 + +- name: Copy openssl.cnf + copy: + src: openssl.cnf + dest: "{{ zookeeper_ca_dir }}/openssl.cnf" + mode: 0755 + +- name: Render certificates + command: "{{ zookeeper_ca_dir }}/zk-ca.sh {{ zookeeper_ca_dir }} localhost" + +- name: Add CA to the configuration + blockinfile: + path: /opt/zookeeper/conf/zoo.cfg + block: | + server.1=localhost:2888:3888 + serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory + secureClientPort=2281 + ssl.keyStore.location={{ zookeeper_ca_dir }}/keystores/localhost.pem + ssl.trustStore.location={{ zookeeper_ca_dir }}/certs/cacert.pem + become: true diff --git a/test-playbooks/ensure-zookeeper.yaml b/test-playbooks/ensure-zookeeper.yaml index cca07ca9c..7e59dc067 100644 --- a/test-playbooks/ensure-zookeeper.yaml +++ b/test-playbooks/ensure-zookeeper.yaml @@ -3,6 +3,8 @@ - name: Include ensure-zookeeper include_role: name: ensure-zookeeper + vars: + zookeeper_use_tls: true - name: Test zookeeper is running command: /opt/zookeeper/bin/zkCli.sh ls /