Verify cert chain after adminep update

This commit checks the validity of the certificate chain
after admin-ep certificate is renewed on subclouds. If
the check fails, the update_admin_ep_cert deletes the secret
and subsequent audits will recreate. This check fixes the
scenario where old ICA was used when updating &
renewing rootCA.

Closes-bug: #1923071

Signed-off-by: Sabeel Ansari <Sabeel.Ansari@windriver.com>
Change-Id: I112dd52e220dcc8bdb72c2c772ede72fbb786c7b
This commit is contained in:
Sabeel Ansari 2021-04-08 14:13:28 -04:00
parent 190b55704d
commit 38ae08893b
3 changed files with 73 additions and 3 deletions

View File

@ -11,18 +11,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
# Copyright (c) 2020-2021 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement.
#
import base64
import json
import os
import re
import requests
import ssl
import tempfile
from eventlet.green import subprocess
from six.moves.urllib.parse import urlparse
from keystoneclient.v3 import client as keystone_client
from keystoneauth1 import session
@ -79,6 +81,65 @@ def update_admin_ep_cert(token, ca_crt, tls_crt, tls_key):
raise Exception('Update admin endpoint certificate failed')
def verify_adminep_cert_chain():
"""
Verify admin endpoint certificate chain & delete if invalid
:param context: an admin context.
:return: True/False if chain is valid
"""
"""
* Retrieve ICA & AdminEP cert secrets from k8s
* base64 decode ICA cert (tls.crt from SC_INTERMEDIATE_CA_SECRET_NAME)
* & adminep (tls.crt from SC_ADMIN_ENDPOINT_SECRET_NAME)
* & store the crts in tempfiles
* Run openssl verify against RootCA to verify the chain
"""
kube_op = sys_kube.KubeOperator()
secret_ica = kube_op.kube_get_secret(constants.SC_INTERMEDIATE_CA_SECRET_NAME,
CERT_NAMESPACE_SUBCLOUD_CONTROLLER)
if 'tls.crt' not in secret_ica.data:
raise Exception('%s tls.crt (ICA) data missing'
% (constants.SC_INTERMEDIATE_CA_SECRET_NAME))
secret_adminep = kube_op.kube_get_secret(constants.SC_ADMIN_ENDPOINT_SECRET_NAME,
CERT_NAMESPACE_SUBCLOUD_CONTROLLER)
if 'tls.crt' not in secret_adminep.data:
raise Exception('%s tls.crt data missing'
% (constants.SC_ADMIN_ENDPOINT_SECRET_NAME))
txt_ca_crt = base64.b64decode(secret_ica.data['tls.crt'])
txt_tls_crt = base64.b64decode(secret_adminep.data['tls.crt'])
with tempfile.NamedTemporaryFile() as ca_tmpfile:
ca_tmpfile.write(txt_ca_crt)
ca_tmpfile.flush()
with tempfile.NamedTemporaryFile() as adminep_tmpfile:
adminep_tmpfile.write(txt_tls_crt)
adminep_tmpfile.flush()
cmd = ['openssl', 'verify', '-CAfile', constants.DC_ROOT_CA_CERT_PATH,
'-untrusted', ca_tmpfile.name, adminep_tmpfile.name]
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
proc.wait()
if 0 == proc.returncode:
LOG.info('verify_adminep_cert_chain passed. Valid chain')
return True
else:
LOG.info('verify_adminep_cert_chain: Chain is invalid\n%s\n%s'
% (stdout, stderr))
res = kube_op.kube_delete_secret(constants.SC_ADMIN_ENDPOINT_SECRET_NAME,
CERT_NAMESPACE_SUBCLOUD_CONTROLLER)
LOG.info('Deleting AdminEP secret due to invalid chain. %s:%s, result %s, msg %s'
% (CERT_NAMESPACE_SUBCLOUD_CONTROLLER,
constants.SC_ADMIN_ENDPOINT_SECRET_NAME,
res.status, res.message))
return False
def dc_get_subcloud_sysinv_url(subcloud_name):
user_auth = v3.Password(
auth_url=CONF.endpoint_cache.auth_uri,

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2020 Wind River Systems, Inc.
# Copyright (c) 2020-2021 Wind River Systems, Inc.
#
# The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms
@ -365,8 +365,16 @@ class AdminEndpointRenew(CertificateRenew):
def update_certificate(self, event_data):
token = self.context.get_token()
role = self.context.dc_role
utils.update_admin_ep_cert(token, event_data.ca_crt, event_data.tls_crt,
event_data.tls_key)
event_data.tls_key)
# In subclouds, it was observed that sometimes old ICA was used
# to sign adminep-cert. Here we run a verification to confirm that
# the chain is valid & delete secret if chain fails
if role == constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD:
utils.verify_adminep_cert_chain()
class DCIntermediateCertRenew(CertificateRenew):

View File

@ -1800,6 +1800,7 @@ CERTIFICATE_TYPE_ADMIN_ENDPOINT_INTERMEDIATE_CA = 'intermediate-ca-cert'
DC_ADMIN_ENDPOINT_SECRET_NAME = 'dc-adminep-certificate'
SC_ADMIN_ENDPOINT_SECRET_NAME = 'sc-adminep-certificate'
SC_INTERMEDIATE_CA_SECRET_NAME = 'sc-adminep-ca-certificate'
DC_ADMIN_ROOT_CA_SECRET_NAME = 'dc-adminep-root-ca-certificate'