Skip to content

Commit 2644ad8

Browse files
authored
Merge pull request xcat2#244 from Obihoernchen/caperm
TLS CA permission fixes
2 parents b812d2a + 63a0cd2 commit 2644ad8

3 files changed

Lines changed: 132 additions & 86 deletions

File tree

confluent_server/builddeb

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,30 @@ if ! grep wheezy /etc/os-release; then
5050
fi
5151
head -n -1 debian/control > debian/control1
5252
mv debian/control1 debian/control
53-
cat > debian/postinst << EOF
54-
if ! getent passwd confluent > /dev/null; then
53+
cat > debian/postinst << \EOF
54+
if ! getent passwd confluent > /dev/null; then
5555
useradd -r confluent -d /var/lib/confluent -s /usr/sbin/nologin
56-
mkdir -p /etc/confluent
57-
chown confluent /etc/confluent
5856
fi
57+
mkdir -p /etc/confluent /var/lib/confluent /var/log/confluent /var/cache/confluent
58+
chown confluent:confluent /etc/confluent /var/lib/confluent /var/log/confluent /var/cache/confluent
59+
60+
sysctl -p /usr/lib/sysctl.d/confluent.conf > /dev/null 2>&1
61+
NEEDCHOWN=0
62+
NEEDSTART=0
63+
[ -n "$(find /etc/confluent /var/log/confluent /var/cache/confluent -uid 0 -print -quit 2>/dev/null)" ] && NEEDCHOWN=1
64+
if [ $NEEDCHOWN = 1 ]; then
65+
if systemctl is-active confluent > /dev/null; then
66+
NEEDSTART=1
67+
systemctl stop confluent
68+
fi
69+
chown -R confluent:confluent /etc/confluent /var/log/confluent /var/cache/confluent
70+
fi
71+
systemctl daemon-reload
72+
if systemctl is-active confluent > /dev/null || [ $NEEDSTART = 1 ]; then systemctl restart confluent > /dev/null 2>&1; fi
73+
if [ ! -e /etc/pam.d/confluent ]; then
74+
ln -s /etc/pam.d/sshd /etc/pam.d/confluent
75+
fi
76+
true
5977
EOF
6078
echo 'export PYBUILD_INSTALL_ARGS=--install-lib=/opt/confluent/lib/python' >> debian/rules
6179
#echo 'Provides: python-'$DPKGNAME >> debian/control

confluent_server/confluent/certutil.py

Lines changed: 109 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -207,85 +207,98 @@ def substitute_cfg(setting, key, val, newval, cfgfile, line):
207207
return False
208208

209209
async def create_full_ca(certout):
210-
mkdirp('/etc/confluent/tls/ca/private')
211-
keyout = '/etc/confluent/tls/ca/private/cakey.pem'
212-
csrout = '/etc/confluent/tls/ca/ca.csr'
213-
mkdirp('/etc/confluent/tls/ca/newcerts')
214-
with open('/etc/confluent/tls/ca/index.txt', 'w') as idx:
215-
pass
216-
with open('/etc/confluent/tls/ca/index.txt.attr', 'w') as idx:
217-
idx.write('unique_subject = no')
218-
with open('/etc/confluent/tls/ca/serial', 'w') as srl:
219-
srl.write('01')
220-
sslcfg = get_openssl_conf_location()
221-
newcfg = '/etc/confluent/tls/ca/openssl.cfg'
222-
settings = {
223-
'dir': '/etc/confluent/tls/ca',
224-
'certificate': '$dir/cacert.pem',
225-
'private_key': '$dir/private/cakey.pem',
226-
'countryName': 'optional',
227-
'stateOrProvinceName': 'optional',
228-
'organizationName': 'optional',
229-
}
230-
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
231-
if len(subj) > 68:
232-
subj = subj[:68]
233-
with open(sslcfg, 'r') as cfgin:
234-
with open(newcfg, 'w') as cfgfile:
235-
for line in cfgin.readlines():
236-
cfg = line.split('#')[0]
237-
if '=' in cfg:
238-
key, val = cfg.split('=', 1)
239-
for stg in settings:
240-
if substitute_cfg(stg, key, val, settings[stg], cfgfile, line):
241-
break
242-
else:
243-
cfgfile.write(line.strip() + '\n')
244-
continue
245-
cfgfile.write(line.strip() + '\n')
246-
cfgfile.write('\n[CACert]\nbasicConstraints = critical,CA:true\nkeyUsage = critical,keyCertSign,cRLSign\n[ca_confluent]\n')
247-
await util.check_call(
248-
'openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
249-
keyout)
250-
await util.check_call(
251-
'openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj', subj)
252-
await util.check_call(
253-
'openssl', 'ca', '-config', newcfg, '-batch', '-selfsign',
254-
'-extensions', 'CACert', '-extfile', newcfg,
255-
'-notext', '-md', 'sha384', '-startdate',
256-
'19700101010101Z', '-enddate', '21000101010101Z', '-keyfile',
257-
keyout, '-out', '/etc/confluent/tls/ca/cacert.pem', '-in', csrout
258-
)
259-
shutil.copy2('/etc/confluent/tls/ca/cacert.pem', certout)
210+
# The CA is used by the confluent service, which runs as the owner of
211+
# /etc/confluent rather than root; create the CA material as that user
212+
# so the service can use the database for issuing certificates
213+
ouid = normalize_uid()
214+
try:
215+
mkdirp('/etc/confluent/tls/ca/private')
216+
keyout = '/etc/confluent/tls/ca/private/cakey.pem'
217+
csrout = '/etc/confluent/tls/ca/ca.csr'
218+
mkdirp('/etc/confluent/tls/ca/newcerts')
219+
with open('/etc/confluent/tls/ca/index.txt', 'w') as idx:
220+
pass
221+
with open('/etc/confluent/tls/ca/index.txt.attr', 'w') as idx:
222+
idx.write('unique_subject = no')
223+
with open('/etc/confluent/tls/ca/serial', 'w') as srl:
224+
srl.write('01')
225+
sslcfg = get_openssl_conf_location()
226+
newcfg = '/etc/confluent/tls/ca/openssl.cfg'
227+
settings = {
228+
'dir': '/etc/confluent/tls/ca',
229+
'certificate': '$dir/cacert.pem',
230+
'private_key': '$dir/private/cakey.pem',
231+
'countryName': 'optional',
232+
'stateOrProvinceName': 'optional',
233+
'organizationName': 'optional',
234+
}
235+
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
236+
if len(subj) > 68:
237+
subj = subj[:68]
238+
with open(sslcfg, 'r') as cfgin:
239+
with open(newcfg, 'w') as cfgfile:
240+
for line in cfgin.readlines():
241+
cfg = line.split('#')[0]
242+
if '=' in cfg:
243+
key, val = cfg.split('=', 1)
244+
for stg in settings:
245+
if substitute_cfg(stg, key, val, settings[stg], cfgfile, line):
246+
break
247+
else:
248+
cfgfile.write(line.strip() + '\n')
249+
continue
250+
cfgfile.write(line.strip() + '\n')
251+
cfgfile.write('\n[CACert]\nbasicConstraints = critical,CA:true\nkeyUsage = critical,keyCertSign,cRLSign\n[ca_confluent]\n')
252+
await util.check_call(
253+
'openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
254+
keyout)
255+
await util.check_call(
256+
'openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj', subj)
257+
await util.check_call(
258+
'openssl', 'ca', '-config', newcfg, '-batch', '-selfsign',
259+
'-extensions', 'CACert', '-extfile', newcfg,
260+
'-notext', '-md', 'sha384', '-startdate',
261+
'19700101010101Z', '-enddate', '21000101010101Z', '-keyfile',
262+
keyout, '-out', '/etc/confluent/tls/ca/cacert.pem', '-in', csrout
263+
)
264+
shutil.copy2('/etc/confluent/tls/ca/cacert.pem', certout)
265+
finally:
266+
os.seteuid(ouid)
260267
#openssl ca -config openssl.cnf -selfsign -keyfile cakey.pem -startdate 20150214120000Z -enddate 20160214120000Z
261268
#20160107071311Z -enddate 20170106071311Z
262269

263270
async def create_simple_ca(keyout, certout):
271+
# As with create_full_ca, the CA material must be owned by the owner
272+
# of /etc/confluent for use by the confluent service
273+
ouid = normalize_uid()
264274
try:
265-
os.makedirs('/etc/confluent/tls')
266-
except OSError as e:
267-
if e.errno != 17:
268-
raise
269-
sslcfg = get_openssl_conf_location()
270-
tmphdl, tmpconfig = tempfile.mkstemp()
271-
os.close(tmphdl)
272-
shutil.copy2(sslcfg, tmpconfig)
273-
await util.check_call(
274-
'openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
275-
keyout)
276-
try:
277-
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
278-
if len(subj) > 68:
279-
subj = subj[:68]
280-
with open(tmpconfig, 'a') as cfgfile:
281-
cfgfile.write('\n[CACert]\nbasicConstraints = critical,CA:true\n')
275+
try:
276+
os.makedirs('/etc/confluent/tls')
277+
except OSError as e:
278+
if e.errno != 17:
279+
raise
280+
sslcfg = get_openssl_conf_location()
281+
tmphdl, tmpconfig = tempfile.mkstemp()
282+
os.close(tmphdl)
283+
shutil.copy2(sslcfg, tmpconfig)
282284
await util.check_call(
283-
'openssl', 'req', '-new', '-x509', '-key', keyout, '-days',
284-
'27300', '-out', certout, '-subj', subj,
285-
'-extensions', 'CACert', '-config', tmpconfig
286-
)
285+
'openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
286+
keyout)
287+
try:
288+
subj = '/CN=Confluent TLS Certificate authority ({0})'.format(socket.gethostname())
289+
if len(subj) > 68:
290+
subj = subj[:68]
291+
with open(tmpconfig, 'a') as cfgfile:
292+
cfgfile.write('\n[CACert]\nbasicConstraints = critical,CA:true\n')
293+
await util.check_call(
294+
'openssl', 'req', '-new', '-x509', '-key', keyout, '-days',
295+
'27300', '-out', certout, '-subj', subj,
296+
'-extensions', 'CACert', '-config', tmpconfig
297+
)
298+
finally:
299+
os.remove(tmpconfig)
287300
finally:
288-
os.remove(tmpconfig)
301+
os.seteuid(ouid)
289302

290303
async def create_certificate(keyout=None, certout=None, csrfile=None, subj=None, san=None, backdate=True, days=None):
291304
now_utc = datetime.datetime.now(datetime.timezone.utc)
@@ -413,12 +426,30 @@ async def create_certificate(keyout=None, certout=None, csrfile=None, subj=None,
413426
shutil.copy2(cacfgfile, tmpcafile)
414427
os.close(tmphdl)
415428
cacfgfile = tmpcafile
416-
await util.check_call(
417-
'openssl', 'ca', '-config', cacfgfile, '-rand_serial',
418-
'-in', csrfile, '-out', certout, '-batch', '-notext',
419-
'-startdate', startdate, '-enddate', enddate, '-md', 'sha384',
420-
'-extfile', extconfig, '-subj', subj
421-
)
429+
os.chmod(cacfgfile, 0o644)
430+
os.chmod(csrfile, 0o644)
431+
# openssl ca rewrites the CA database (index, serial) as the
432+
# invoking user; run it as the owner of /etc/confluent so the
433+
# database remains usable by the confluent service. The chmodded
434+
# temporary inputs hold no secrets, and the certificate is
435+
# written to a temporary path first, as certout may only be
436+
# writable by the original user (e.g. a web server certificate
437+
# path during osdeploy initialize -t)
438+
os.chmod(extconfig, 0o644)
439+
ouid = normalize_uid()
440+
try:
441+
tmphdl, tmpcertout = tempfile.mkstemp()
442+
os.close(tmphdl)
443+
await util.check_call(
444+
'openssl', 'ca', '-config', cacfgfile, '-rand_serial',
445+
'-in', csrfile, '-out', tmpcertout, '-batch', '-notext',
446+
'-startdate', startdate, '-enddate', enddate, '-md', 'sha384',
447+
'-extfile', extconfig, '-subj', subj
448+
)
449+
finally:
450+
os.seteuid(ouid)
451+
shutil.copy(tmpcertout, certout)
452+
os.remove(tmpcertout)
422453
for keycopy in tlsmateriallocation.get('keys', []):
423454
if keycopy != keyout:
424455
shutil.copy2(keyout, keycopy)

confluent_server/confluent_server.spec.tmpl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,7 @@ chown confluent:confluent /etc/confluent /var/lib/confluent /var/log/confluent /
6868
sysctl -p /usr/lib/sysctl.d/confluent.conf >& /dev/null
6969
NEEDCHOWN=0
7070
NEEDSTART=0
71-
find /etc/confluent -uid 0 | grep -E '.*' > /dev/null && NEEDCHOWN=1
72-
find /var/log/confluent -uid 0 | grep -E '.*' > /dev/null && NEEDCHOWN=1
73-
find /var/run/confluent -uid 0 | grep -E '.*' > /dev/null && NEEDCHOWN=1
74-
find /var/cache/confluent -uid 0 | grep -E '.*' > /dev/null && NEEDCHOWN=1
71+
[ -n "$(find /etc/confluent /var/log/confluent /var/cache/confluent -uid 0 -print -quit 2>/dev/null)" ] && NEEDCHOWN=1
7572
if [ $NEEDCHOWN = 1 ]; then
7673
if systemctl is-active confluent > /dev/null; then
7774
NEEDSTART=1

0 commit comments

Comments
 (0)