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 # See the License for the specific language governing permissions and
# limitations under the License. # 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 # The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms # of this software may be licensed only pursuant to the terms
# of an applicable Wind River license agreement. # of an applicable Wind River license agreement.
# #
import base64
import json import json
import os import os
import re import re
import requests import requests
import ssl import ssl
import tempfile import tempfile
from eventlet.green import subprocess
from six.moves.urllib.parse import urlparse from six.moves.urllib.parse import urlparse
from keystoneclient.v3 import client as keystone_client from keystoneclient.v3 import client as keystone_client
from keystoneauth1 import session 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') 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): def dc_get_subcloud_sysinv_url(subcloud_name):
user_auth = v3.Password( user_auth = v3.Password(
auth_url=CONF.endpoint_cache.auth_uri, auth_url=CONF.endpoint_cache.auth_uri,

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # 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 # The right to copy, distribute, modify, or otherwise make use
# of this software may be licensed only pursuant to the terms # of this software may be licensed only pursuant to the terms
@ -365,8 +365,16 @@ class AdminEndpointRenew(CertificateRenew):
def update_certificate(self, event_data): def update_certificate(self, event_data):
token = self.context.get_token() token = self.context.get_token()
role = self.context.dc_role
utils.update_admin_ep_cert(token, event_data.ca_crt, event_data.tls_crt, 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): 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' DC_ADMIN_ENDPOINT_SECRET_NAME = 'dc-adminep-certificate'
SC_ADMIN_ENDPOINT_SECRET_NAME = 'sc-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' DC_ADMIN_ROOT_CA_SECRET_NAME = 'dc-adminep-root-ca-certificate'