Thanks for your pointers. But I will have to tell they are still at 10000 feet level.
As a first step to associate certificates and keys I did the following, especially for my setup with a master and a minion.
a) After reading about ssl I created a custom script that does the following.
--> create a root authority
--> create a intermediate authority
---> create certificates and keys for all nodes in setup (defined by nodes.yaml file)
I patched the openssl.cnf file to have req_extensions to have SANs included. SAN definition, is part of nodes.yaml
dir view:
---> contains
openssl.cnf.ca /* patched for SAN */
---> nodes.yaml /* defines cluster */
---> certutil.py /* a python script that does everything, it is not fully automated though */
1) Creates a Root CA Authority (give CN=RootAuth)
2) Creates an Intermediate CA Authority and a CA Chain (give CN=InterAuth)
3) Creates keys and certificates for all nodes in the cluster signed by the intermediate authority.
< Invoke as python certutil.py>
After this, I created truststore and keystore files as below.
keytool -import -file 'intermediate/cert/ca-chain.cert.pem' -alias ca \
-storetype pkcs12 -storepass ponies -keystore dev_and_test_truststore.p12
~ openssl pkcs12 -export -in intermediate/cert/master.cert.pem \
-inkey intermediate/private/master.key.pem -out dev_and_test_keystore.p12
Copied server/src/main/resources/keywhiz-development.yaml.h2 as keywhiz-development.yaml
And modified truststore and keystore paths. Left the others as default.
The app crashes with certificate invalid. I had the certs validated through openssl, they seem fine.
Any pointers to get through setting up certificates for this cluster environment?
I have attached the files for your reference here. Your inputs much appreciated.
certutil.py:
=================================================
import yaml
import os
import shutil
import sys
import tempfile
import stat
# needed inputs
CONF="openssl.cnf.ca" # Root CA configuration
INTER="1nt3rm3d1@t3" # Intermediate Authority password
SECRET="s3cr3t" # Root AUthority password
TESTBED='nodes.yaml' # this is yaml file that describes the testbed
def setup_dir(workd, newconf):
shutil.copy(CONF, newconf)
for i in ["certs", "crl", "newcerts", "private", "csr"]:
os.mkdir("%s/%s" %(workd, i))
open("%s/index.txt" % workd, 'w').close()
#chmod 700 private
os.chmod("%s/private" % workd, stat.S_IRWXU)
for i in ["serial", "crlnumber"]:
with open("%s/%s" %(workd, i), "w") as myfile:
myfile.write("1000")
#touch index.txt
#echo 1000 > serial
#echo 1000 > crlnumber
#sed -i "s#^dir\(.*\)=.*#dir\1= $dir#" $CONF
os.system("sed -i.bak \"s#^dir.*=.*#dir = %s#\" %s" % (workd, newconf))
#popd
def create_secure_key(passwd, out):
cmd="openssl genrsa -aes256 -passout pass:%s -out %s 4096" % (passwd, out)
os.system(cmd)
def create_key(out):
cmd="openssl genrsa -out %s 2048" % out
os.system(cmd)
def create_root_cert(conffile, key, keypass, outcert):
cmd="openssl req -config %s -key %s -passin pass:%s -new -x509 -days 7300 -sha256 -extensions v3_ca -out %s" % \
(conffile, key, keypass, outcert)
os.system( cmd)
os.chmod(outcert, stat.S_IREAD)
def patch_intermediate_config_properties():
#sed -i "s#^dir\(.*\)=.*#dir\1= $int#" $int/$CONF
os.system("sed -i.bak \"s#^dir.*=.*#dir = %s#\" %s" %(inter, INTERCACONF))
#sed -i "s#^private_key\(.*\)=.*#private_key\1= \$dir/private/intermediate.key.pem#" $int/$CONF
os.system("sed -i \"s#^private_key.*=.*#private_key = \$dir/private/intermediate.key.pem#\" %s" % INTERCACONF)
#sed -i "s#^certificate\(.*\)=.*#certificate\1= \$dir/certs/intermediate.cert.pem#" $int/$CONF
os.system("sed -i \"s#^certificate.*=.*#certificate = \$dir/certs/intermediate.cert.pem#\" %s" % INTERCACONF)
#sed -i "s#^crl\(.*\)=.*#crl\1= \$dir/crl/intermediate.crl.pem#" $int/$CONF
os.system("sed -i \"s#^crl.*=.*#crl = \$dir/crl/intermediate.crl.pem#\" %s" % INTERCACONF)
#sed -i "s/^policy\(.*\)=.*/policy\1= policy_loose/" $int/$CONF
os.system("sed -i \"s/^policy.*=.*/policy = policy_loose/\" %s" % INTERCACONF)
def create_csr_with_secure_key(conffile, key, keypass, outcsr):
# openssl req -config $CONF -key private/intermediate.key.pem -passin pass:$INTER -new -sha256 -out csr/intermediate.csr.pem
os.system("openssl req -config %s -key %s -passin pass:%s -new -sha256 -out %s" % (conffile, key, keypass, outcsr))
def create_csr(conffile, key, outcsr):
# openssl req -config $CONF -key private/node.key.pem -new -sha256 -out csr/node.csr.pem
os.system("openssl req -config %s -key %s -new -sha256 -out %s" % (conffile, key, outcsr))
#$(cd "$dir" && openssl ca -config $CONF -passin pass:$SECRET -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem)
def create_inter_cert(caconf, capass, csr, outcert):
os.system("openssl ca -config %s -passin pass:%s -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in %s -out %s" % \
(caconf, capass, csr, outcert))
def create_server_cert(caconf, capass, csr, outcert):
os.system("openssl ca -config %s -passin pass:%s -extensions server_cert -extensions v3_req -days 375 -notext -md sha256 -in %s -out %s" % (caconf, capass, csr, outcert))
def create_client_cert(caconf, capass, csr, outcert):
os.system("openssl ca -config %s -passin pass:%s -extensions usr_cert -extensions v3_req -days 375 -notext -md sha256 -in %s -out %s" % (caconf, capass, csr, outcert))
print "1. Setup top directory"
top=tempfile.mkdtemp(prefix="CERT", dir=os.getcwd())
inter="%s/intermediate" % top
os.mkdir(inter)
shutil.copy(TESTBED, top)
print "initializing top directory.. %s" %(top)
CACONF="%s/%s" % (top,CONF)
CAKEY="%s/private/ca.key.pem" % (top)
CACERT="%s/certs/ca.cert.pem" % (top)
setup_dir(top, CACONF)
INTERCACONF="%s/%s" % (inter, CONF)
INTERCAKEY="%s/private/intermediate.key.pem" % (inter)
INTERCACERT="%s/certs/intermediate.cert.pem" % (inter)
INTERCACSR="%s/csr/intermediate.csr.pem" % (inter)
setup_dir(inter, INTERCACONF)
CACHAIN="%s/certs/ca-chain.cert.pem" % (inter)
print "2. Create root key"
#openssl genrsa -aes256 -passout pass:$SECRET -out $top/private/ca.key.pem 4096
create_secure_key(SECRET, CAKEY)
print "3. create root certificate"
create_root_cert(CACONF, CAKEY, SECRET, CACERT)
#$(cd "$dir" && openssl req -config $CONF -key private/ca.key.pem -passin pass:$SECRET -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem)
print "4. Prepare intermediatary certificate"
patch_intermediate_config_properties()
print "5. create intermediate key"
create_secure_key(INTER, INTERCAKEY)
print "6. create intermediate request"
#$(cd "$int" && openssl req -config $CONF -key private/intermediate.key.pem -passin pass:$INTER -new -sha256 -out csr/intermediate.csr.pem)
create_csr_with_secure_key(INTERCACONF, INTERCAKEY, INTER, INTERCACSR)
print "7. Sign intermediate request to create a certificate"
#$(cd "$dir" && openssl ca -config $CONF -passin pass:$SECRET -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem)
create_inter_cert(CACONF, SECRET, INTERCACSR, INTERCACERT)
print "8. Install root certificate in all clients"
print "9. create ca trust chain, to enable clients without knowing root to validate successfully."
#cat $int/certs/intermediate.cert.pem $dir/certs/ca.cert.pem > $int/certs/ca-chain.cert.pem
shutil.copy(INTERCACERT, CACHAIN)
with open(CACHAIN, "ab") as f:
with open(CACERT, "rb") as s:
f.write(s.read())
print "10. creating certs for nodes in TESTED[%s] based on conf file %s" % (TESTBED, INTERCACONF)
s=open(TESTBED,'r')
d=yaml.safe_load(s)
for node,info in d.items():
print "Node: ", node
print "Server: ", info.get('server', False)
print "IP: ", info.get('ip', "127.0.0.1")
print "DNS: ", info.get('dns', "localhost")
# create and patch conf file for each node specific to SAN
nconf="%s/%s-%s" %(inter, node,CONF)
nkey="%s/private/%s.key.pem" % (inter, node)
ncsr="%s/csr/%s.csr.pem" % (inter, node)
ncert="%s/certs/%s.cert.pem" % (inter, node)
shutil.copy(INTERCACONF, nconf)
os.system('sed -i.bak \"/\[ alt_names \]/,+3d\" %s' % nconf)
with open(nconf, "a") as myfile:
myfile.write("\n")
myfile.write("[ alt_names ]\n")
for index, val in enumerate(info.get('ip', "127.0.0.1")):
myfile.write("IP.%d=%s\n" %(index, val))
for index, name in enumerate(info.get('dns', "localhost")):
myfile.write("DNS.%d=%s\n" % (index, name))
# omit -aes256 to drop passwords for key
# openssl genrsa -aes256 -passout pass:$INTER -out intermediate/private/key 2048
create_key(nkey)
# create csr
# config file is updated with SAN (ip/dns)
create_csr(nconf, nkey, ncsr)
# create cert signed with intermediate certificate auth
if info.get('server', False):
create_server_cert(nconf, INTER, ncsr, ncert)
else:
create_client_cert(nconf, INTER, ncsr, ncert)
print "All done"
=================================================
The testbed definition...
nodes.yaml:
==================================================
master:
server: true
ip:
- 127.0.0.1
- 10.134.193.180
dns:
- localhost
- master
minion:
server: false
ip:
- 10.134.194.187
dns:
- minion
==================================================
3. openssl cnf file
===========================================
# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = /home/cephadm/certs/root/ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
req_extensions = v3_req
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = US
stateOrProvinceName_default = California
localityName_default = Fremont
0.organizationName_default = DemoStore
organizationalUnitName_default = Certs
emailAddress_default = de...@demostore.org
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
# below has to be the last few lines (script assumes so)
[ alt_names ]
DNS.1=localhost
IP.1=127.0.0.1
===========================================