mirror of
https://github.com/xcat2/confluent.git
synced 2024-11-26 03:19:48 +00:00
5ee6d0ca5d
The -text was between startdate and its argument
270 lines
10 KiB
Python
270 lines
10 KiB
Python
import os
|
|
import confluent.collective.manager as collective
|
|
import confluent.util as util
|
|
from os.path import exists
|
|
import shutil
|
|
import socket
|
|
import eventlet.green.subprocess as subprocess
|
|
import tempfile
|
|
|
|
def mkdirp(targ):
|
|
try:
|
|
return os.makedirs(targ)
|
|
except OSError as e:
|
|
if e.errno != 17:
|
|
raise
|
|
|
|
def get_openssl_conf_location():
|
|
if exists('/etc/pki/tls/openssl.cnf'):
|
|
return '/etc/pki/tls/openssl.cnf'
|
|
elif exists('/etc/ssl/openssl.cnf'):
|
|
return '/etc/ssl/openssl.cnf'
|
|
else:
|
|
raise Exception("Cannot find openssl config file")
|
|
|
|
def normalize_uid():
|
|
curruid = os.geteuid()
|
|
neededuid = os.stat('/etc/confluent').st_uid
|
|
if curruid != neededuid:
|
|
os.seteuid(neededuid)
|
|
if os.geteuid() != neededuid:
|
|
raise Exception('Need to run as root or owner of /etc/confluent')
|
|
return curruid
|
|
|
|
def get_ip_addresses():
|
|
lines, _ = util.run(['ip', 'addr'])
|
|
if not isinstance(lines, str):
|
|
lines = lines.decode('utf8')
|
|
for line in lines.split('\n'):
|
|
if line.startswith(' inet6 '):
|
|
line = line.replace(' inet6 ', '').split('/')[0]
|
|
if line == '::1':
|
|
continue
|
|
elif line.startswith(' inet '):
|
|
line = line.replace(' inet ', '').split('/')[0]
|
|
if line == '127.0.0.1':
|
|
continue
|
|
if line.startswith('169.254.'):
|
|
continue
|
|
else:
|
|
continue
|
|
yield line
|
|
|
|
def check_apache_config(path):
|
|
keypath = None
|
|
certpath = None
|
|
with open(path, 'r') as openf:
|
|
webconf = openf.read()
|
|
for line in webconf.split('\n'):
|
|
line = line.strip()
|
|
line = line.split('#')[0]
|
|
if line.startswith('SSLCertificateFile'):
|
|
_, certpath = line.split(None, 1)
|
|
if line.startswith('SSLCertificateKeyFile'):
|
|
_, keypath = line.split(None, 1)
|
|
return keypath, certpath
|
|
|
|
def get_certificate_paths():
|
|
keypath = None
|
|
certpath = None
|
|
if os.path.exists('/etc/httpd/conf.d/ssl.conf'): # redhat way
|
|
keypath, certpath = check_apache_config('/etc/httpd/conf.d/ssl.conf')
|
|
if not keypath and os.path.exists('/etc/apache2'): # suse way
|
|
for currpath, _, files in os.walk('/etc/apache2'):
|
|
for fname in files:
|
|
if fname.endswith('.template'):
|
|
continue
|
|
kploc = check_apache_config(os.path.join(currpath,
|
|
fname))
|
|
if keypath and kploc[0]:
|
|
return None, None # Ambiguous...
|
|
if kploc[0]:
|
|
keypath, certpath = kploc
|
|
|
|
return keypath, certpath
|
|
|
|
def assure_tls_ca():
|
|
keyout, certout = ('/etc/confluent/tls/cakey.pem', '/etc/confluent/tls/cacert.pem')
|
|
if not os.path.exists(certout):
|
|
#create_simple_ca(keyout, certout)
|
|
create_full_ca(certout)
|
|
fname = '/var/lib/confluent/public/site/tls/{0}.pem'.format(
|
|
collective.get_myname())
|
|
ouid = normalize_uid()
|
|
try:
|
|
os.makedirs(os.path.dirname(fname))
|
|
except OSError as e:
|
|
if e.errno != 17:
|
|
raise
|
|
finally:
|
|
os.seteuid(ouid)
|
|
shutil.copy2('/etc/confluent/tls/cacert.pem', fname)
|
|
hv, _ = util.run(
|
|
['openssl', 'x509', '-in', '/etc/confluent/tls/cacert.pem', '-hash', '-noout'])
|
|
if not isinstance(hv, str):
|
|
hv = hv.decode('utf8')
|
|
hv = hv.strip()
|
|
hashname = '/var/lib/confluent/public/site/tls/{0}.0'.format(hv)
|
|
certname = '{0}.pem'.format(collective.get_myname())
|
|
for currname in os.listdir('/var/lib/confluent/public/site/tls/'):
|
|
currname = os.path.join('/var/lib/confluent/public/site/tls/', currname)
|
|
if currname.endswith('.0'):
|
|
try:
|
|
realname = os.readlink(currname)
|
|
if realname == certname:
|
|
os.unlink(currname)
|
|
except OSError:
|
|
pass
|
|
os.symlink(certname, hashname)
|
|
|
|
def substitute_cfg(setting, key, val, newval, cfgfile, line):
|
|
if key.strip() == setting:
|
|
cfgfile.write(line.replace(val, newval) + '\n')
|
|
return True
|
|
return False
|
|
|
|
def create_full_ca(certout):
|
|
mkdirp('/etc/confluent/tls/ca/private')
|
|
keyout = '/etc/confluent/tls/ca/private/cakey.pem'
|
|
csrout = '/etc/confluent/tls/ca/ca.csr'
|
|
mkdirp('/etc/confluent/tls/ca/newcerts')
|
|
with open('/etc/confluent/tls/ca/index.txt', 'w') as idx:
|
|
pass
|
|
with open('/etc/confluent/tls/ca/index.txt.attr', 'w') as idx:
|
|
idx.write('unique_subject = no')
|
|
with open('/etc/confluent/tls/ca/serial', 'w') as srl:
|
|
srl.write('01')
|
|
sslcfg = get_openssl_conf_location()
|
|
newcfg = '/etc/confluent/tls/ca/openssl.cfg'
|
|
settings = {
|
|
'dir': '/etc/confluent/tls/ca',
|
|
'certificate': '$dir/cacert.pem',
|
|
'private_key': '$dir/private/cakey.pem',
|
|
'countryName': 'optional',
|
|
'stateOrProvinceName': 'optional',
|
|
'organizationName': 'optional',
|
|
}
|
|
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
|
|
if len(subj) > 68:
|
|
subj = subj[:68]
|
|
with open(sslcfg, 'r') as cfgin:
|
|
with open(newcfg, 'w') as cfgfile:
|
|
for line in cfgin.readlines():
|
|
cfg = line.split('#')[0]
|
|
if '=' in cfg:
|
|
key, val = cfg.split('=', 1)
|
|
for stg in settings:
|
|
if substitute_cfg(stg, key, val, settings[stg], cfgfile, line):
|
|
break
|
|
else:
|
|
cfgfile.write(line.strip() + '\n')
|
|
continue
|
|
cfgfile.write(line.strip() + '\n')
|
|
cfgfile.write('\n[CACert]\nbasicConstraints = CA:true\n\n[ca_confluent]\n')
|
|
subprocess.check_call(
|
|
['openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
|
|
keyout])
|
|
subprocess.check_call(
|
|
['openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj', subj])
|
|
subprocess.check_call(
|
|
['openssl', 'ca', '-config', newcfg, '-batch', '-selfsign',
|
|
'-extensions', 'CACert', '-extfile', newcfg,
|
|
'-notext', '-startdate',
|
|
'19700101010101Z', '-enddate', '21000101010101Z', '-keyfile',
|
|
keyout, '-out', '/etc/confluent/tls/ca/cacert.pem', '-in', csrout]
|
|
)
|
|
shutil.copy2('/etc/confluent/tls/ca/cacert.pem', certout)
|
|
#openssl ca -config openssl.cnf -selfsign -keyfile cakey.pem -startdate 20150214120000Z -enddate 20160214120000Z
|
|
#20160107071311Z -enddate 20170106071311Z
|
|
|
|
def create_simple_ca(keyout, certout):
|
|
try:
|
|
os.makedirs('/etc/confluent/tls')
|
|
except OSError as e:
|
|
if e.errno != 17:
|
|
raise
|
|
sslcfg = get_openssl_conf_location()
|
|
tmphdl, tmpconfig = tempfile.mkstemp()
|
|
os.close(tmphdl)
|
|
shutil.copy2(sslcfg, tmpconfig)
|
|
subprocess.check_call(
|
|
['openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
|
|
keyout])
|
|
try:
|
|
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
|
|
if len(subj) > 68:
|
|
subj = subj[:68]
|
|
with open(tmpconfig, 'a') as cfgfile:
|
|
cfgfile.write('\n[CACert]\nbasicConstraints = CA:true\n')
|
|
subprocess.check_call([
|
|
'openssl', 'req', '-new', '-x509', '-key', keyout, '-days',
|
|
'27300', '-out', certout, '-subj', subj,
|
|
'-extensions', 'CACert', '-config', tmpconfig
|
|
])
|
|
finally:
|
|
os.remove(tmpconfig)
|
|
|
|
def create_certificate(keyout=None, certout=None):
|
|
if not keyout:
|
|
keyout, certout = get_certificate_paths()
|
|
if not keyout:
|
|
raise Exception('Unable to locate TLS certificate path automatically')
|
|
assure_tls_ca()
|
|
shortname = socket.gethostname().split('.')[0]
|
|
longname = shortname # socket.getfqdn()
|
|
subprocess.check_call(
|
|
['openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
|
|
keyout])
|
|
san = ['IP:{0}'.format(x) for x in get_ip_addresses()]
|
|
# It is incorrect to put IP addresses as DNS type. However
|
|
# there exists non-compliant clients that fail with them as IP
|
|
san.extend(['DNS:{0}'.format(x) for x in get_ip_addresses()])
|
|
san.append('DNS:{0}'.format(shortname))
|
|
#san.append('DNS:{0}'.format(longname))
|
|
san = ','.join(san)
|
|
sslcfg = get_openssl_conf_location()
|
|
tmphdl, tmpconfig = tempfile.mkstemp()
|
|
os.close(tmphdl)
|
|
tmphdl, extconfig = tempfile.mkstemp()
|
|
os.close(tmphdl)
|
|
tmphdl, csrout = tempfile.mkstemp()
|
|
os.close(tmphdl)
|
|
shutil.copy2(sslcfg, tmpconfig)
|
|
serialnum = '0x' + ''.join(['{:02x}'.format(x) for x in bytearray(os.urandom(20))])
|
|
try:
|
|
with open(tmpconfig, 'a') as cfgfile:
|
|
cfgfile.write('\n[SAN]\nsubjectAltName={0}'.format(san))
|
|
with open(extconfig, 'a') as cfgfile:
|
|
cfgfile.write('\nbasicConstraints=CA:false\nsubjectAltName={0}'.format(san))
|
|
subprocess.check_call([
|
|
'openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj',
|
|
'/CN={0}'.format(longname),
|
|
'-extensions', 'SAN', '-config', tmpconfig
|
|
])
|
|
if os.path.exists('/etc/confluent/tls/cakey.pem'):
|
|
subprocess.check_call([
|
|
'openssl', 'x509', '-req', '-in', csrout,
|
|
'-CA', '/etc/confluent/tls/cacert.pem',
|
|
'-CAkey', '/etc/confluent/tls/cakey.pem',
|
|
'-set_serial', serialnum, '-out', certout, '-days', '27300',
|
|
'-extfile', extconfig
|
|
])
|
|
else:
|
|
subprocess.check_call([
|
|
'openssl', 'ca', '-config', '/etc/confluent/tls/ca/openssl.cfg',
|
|
'-in', csrout, '-out', certout, '-batch', '-notext',
|
|
'-startdate', '19700101010101Z', '-enddate', '21000101010101Z',
|
|
'-extfile', extconfig
|
|
])
|
|
finally:
|
|
os.remove(tmpconfig)
|
|
os.remove(csrout)
|
|
os.remove(extconfig)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
outdir = os.getcwd()
|
|
keyout = os.path.join(outdir, 'key.pem')
|
|
certout = os.path.join(outdir, 'cert.pem')
|
|
create_certificate(keyout, certout)
|