From 2b5e706fe3c87d4742350726032daef0bc3b617c Mon Sep 17 00:00:00 2001 From: Andy Ning Date: Thu, 22 Sep 2022 13:21:24 -0400 Subject: [PATCH] Configure sssd for subcloud to access central openldap This change updated sssd and ldap sysinv puppet plugin to generate proper hieradata for puppet to create sssd configuration and openldap clients' configuration (ldap.conf, ldapscripts.conf) for subcloud. With these configuration, sssd and openldap clients on subcloud can access secure openldap running on System Controller. Test Plan: PASS: DC system controller and subcloud deployment. PASS: On subcloud, verify openldap users are accessible by ldapsearch -xH ldaps:// -b "ou=People,dc=cgcs,dc=local" PASS: On subcloud, verify openldap users are accessible by ldapfinger PASS: On subcloud, verify default openldap users (admin, operator) can login on console. PASS: On subcloud, verify openldap users are cached by: getent passwd PASS: On system controller, create new openldap user, verify the new user can login to subcloud on console and by ssh. PASS: On system controller, verify openldap users are cached by: getent passwd PASS: AIO-SX deploymnet, verify bootstrap and unlock succeeds. PASS: AIO-SX system lock/unlock, verify system boots up into normal condition, and openldap functions as expected. Story: 2009834 Task: 46600 Depends-On: https://review.opendev.org/c/starlingx/ansible-playbooks/+/861782 Signed-off-by: Andy Ning Change-Id: I831aef7896bf16d67cef9dee7d4590c393fd1792 --- sysinv/sysinv/sysinv/sysinv/common/utils.py | 30 ++++++++++++++ sysinv/sysinv/sysinv/sysinv/puppet/ldap.py | 43 ++++++++++++++------- sysinv/sysinv/sysinv/sysinv/puppet/sssd.py | 33 ++++++++++++++-- 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index 2715182a23..a0c2cc78be 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -3350,6 +3350,36 @@ def get_certificate_from_secret(secret_name, secret_ns): return tls_crt, tls_key +def get_ca_certificate_from_opaque_secret(secret_name, secret_ns): + """ + Get a CA certificate from a k8s opaque secret (tls secret requires + both tls.crt and tls.key present, a CA certificate alone can be stored + as an opaque secret ca.crt) + :param secret_name: the name of the secret + :param secret_ns: the namespace of the secret + :return: ca_crt: the CA certificate. + raise Exception for kubernetes data errors + """ + kube = kubernetes.KubeOperator() + secret = kube.kube_get_secret(secret_name, secret_ns) + + if not hasattr(secret, 'data'): + raise Exception('Invalid secret %s\\%s' % (secret_ns, secret_name)) + + data = secret.data + if 'ca.crt' not in data: + raise Exception('Invalid CA certificate data from secret %s\\%s' % + (secret_ns, secret_name)) + + try: + ca_crt = base64.decode_as_text(data['ca.crt']) + except TypeError: + raise Exception('CA certificate secret data is invalid %s\\%s' % + (secret_ns, secret_name)) + + return ca_crt + + def verify_ca_crt(crt): cmd = ['openssl', 'verify'] proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/ldap.py b/sysinv/sysinv/sysinv/sysinv/puppet/ldap.py index 93e9201527..0309ce5794 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/ldap.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/ldap.py @@ -52,24 +52,37 @@ class LdapPuppet(base.BasePuppet): def get_secure_system_config(self): config = {} - is_subcloud = \ - self._distributed_cloud_role() == constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD - # Retrieve openldap CA certificate, and server certificate/key - if self._is_openldap_certificate_created() and not is_subcloud: - ldap_ca_cert, _ = utils.get_certificate_from_secret( - constants.OPENLDAP_CA_CERT_SECRET_NAME, - constants.CERT_NAMESPACE_PLATFORM_CA_CERTS) + # Retrieve openldap CA certificate, and server certificate/key. + # For subcloud, only CA certificate is needed. + if self._is_openldap_certificate_created(): + is_subcloud = \ + self._distributed_cloud_role() == \ + constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD - ldap_cert, ldap_key = utils.get_certificate_from_secret( - constants.OPENLDAP_CERT_SECRET_NAME, - constants.CERT_NAMESPACE_PLATFORM_CERTS) + if is_subcloud: + ldap_ca_cert = utils.get_ca_certificate_from_opaque_secret( + constants.OPENLDAP_CA_CERT_SECRET_NAME, + constants.CERT_NAMESPACE_PLATFORM_CA_CERTS) - config.update({ - 'platform::ldap::params::secure_cert': ldap_cert, - 'platform::ldap::params::secure_key': ldap_key, - 'platform::ldap::params::ca_cert': ldap_ca_cert, - }) + config.update({ + 'platform::ldap::params::ca_cert': ldap_ca_cert, + }) + + else: + ldap_ca_cert, _ = utils.get_certificate_from_secret( + constants.OPENLDAP_CA_CERT_SECRET_NAME, + constants.CERT_NAMESPACE_PLATFORM_CA_CERTS) + + ldap_cert, ldap_key = utils.get_certificate_from_secret( + constants.OPENLDAP_CERT_SECRET_NAME, + constants.CERT_NAMESPACE_PLATFORM_CERTS) + + config.update({ + 'platform::ldap::params::secure_cert': ldap_cert, + 'platform::ldap::params::secure_key': ldap_key, + 'platform::ldap::params::ca_cert': ldap_ca_cert, + }) return config diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/sssd.py b/sysinv/sysinv/sysinv/sysinv/puppet/sssd.py index d03154d81d..6df1f02330 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/sssd.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/sssd.py @@ -154,6 +154,7 @@ class SssdPuppet(base.BasePuppet): def _get_local_domain(self): binding_pass = self._get_keyring_password(self.SERVICE_NAME, self.SERVICE_USER) + ldap_uri = self._get_local_domain_uri() # sssd supports the debug levels (from sssd.conf manual page): # 0, 0x0010: Fatal failures. Anything that would prevent SSSD @@ -178,6 +179,8 @@ class SssdPuppet(base.BasePuppet): # # Debug level: 0x0270, includes fatal failures, critical failures, # serious failures and function data. + + # Default is to bind anonymously. domain_parameters = { 'cache_credentials': 'true', 'debug_level': '0x0270', @@ -187,14 +190,21 @@ class SssdPuppet(base.BasePuppet): 'ldap_search_base': 'dc=cgcs,dc=local', 'ldap_user_home_directory': '/home/$cn', 'ldap_user_shell': '/bin/bash', - 'ldap_uri': 'ldaps://controller/', + 'ldap_uri': ldap_uri, 'ldap_tls_cacert': '/etc/ssl/certs/ca-certificates.crt', - 'ldap_default_bind_dn': 'CN=ldapadmin,DC=cgcs,DC=local', - 'ldap_default_authtok_type': 'password', - 'ldap_default_authtok': binding_pass, 'fallback_homedir': '/home/%u', } + # bind to 'CN=ldapadmin,DC=cgcs,DC=local' using password if + # this is not a DC Subcloud. + if self._distributed_cloud_role() != \ + constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD: + domain_parameters.update({ + 'ldap_default_bind_dn': 'CN=ldapadmin,DC=cgcs,DC=local', + 'ldap_default_authtok_type': 'password', + 'ldap_default_authtok': binding_pass, + }) + return domain_parameters def _get_ldap_domain(self, domain): @@ -290,3 +300,18 @@ class SssdPuppet(base.BasePuppet): } return pam_parameters + + def _get_local_domain_uri(self): + ldapserver_host = constants.CONTROLLER + if self._distributed_cloud_role() == \ + constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD: + sys_controller_network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_SYSTEM_CONTROLLER) + sys_controller_network_addr_pool = self.dbapi.address_pool_get( + sys_controller_network.pool_uuid) + ldapserver_addr = sys_controller_network_addr_pool.floating_address + ldapserver_host = self._format_url_address(ldapserver_addr) + + ldapserver_uri = 'ldaps://%s' % ldapserver_host + + return ldapserver_uri