Optional https for containerized openstack
The certificate for openstack services are installed and stored under /etc/ssl/private/openstack. The endpoint tls parameters are configured by the helm overrides. Tests performed: AIO-SX: application apply, reapply and launch instance AIO-DX: application apply, reapply and launch instance Standard system: application apply, reapply and launch instance Pause and Resume instance. Ensure that no audit error is seen. Story: 2004433 Task: 28096 Change-Id: Ib81f9541ebf116dee817e0b55f31866ed0d283f0 Signed-off-by: Teresa Ho <teresa.ho@windriver.com>
This commit is contained in:
parent
3b126c2f43
commit
2336e855bd
|
@ -299,6 +299,21 @@ start()
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -e $CONFIG_DIR/openstack ]
|
||||
then
|
||||
if [ ! -e /etc/ssl/private/openstack ]
|
||||
then
|
||||
mkdir -p /etc/ssl/private/openstack
|
||||
chmod 755 /etc/ssl/private/openstack
|
||||
fi
|
||||
|
||||
cp -p $CONFIG_DIR/openstack/* /etc/ssl/private/openstack
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
fatal_error "Unable to copy openstack certificate files"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -e $CONFIG_DIR/iptables.rules ]
|
||||
then
|
||||
cp $CONFIG_DIR/iptables.rules /etc/platform/iptables.rules
|
||||
|
|
|
@ -288,7 +288,10 @@ secrets:
|
|||
identity:
|
||||
admin: nova-keystone-admin
|
||||
nova: nova-keystone-user
|
||||
|
||||
tls:
|
||||
compute:
|
||||
api_proxy:
|
||||
public: nova-api-proxy-tls-public
|
||||
|
||||
manifests:
|
||||
configmap_bin: true
|
||||
|
|
|
@ -27,6 +27,15 @@ class platform::client
|
|||
mode => '0644',
|
||||
content => generate('/usr/bin/openstack', 'complete'),
|
||||
}
|
||||
|
||||
if $::personality == 'controller' {
|
||||
file {'/etc/ssl/private/openstack':
|
||||
ensure => 'directory',
|
||||
owner => 'root',
|
||||
group => 'root',
|
||||
mode => '0755',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class platform::client::credentials::params (
|
||||
|
|
|
@ -70,7 +70,7 @@ def do_certificate_list(cc, args):
|
|||
@utils.arg('-m', '--mode',
|
||||
metavar='<mode>',
|
||||
help="optional mode: 'tpm_mode', 'murano', 'murano_ca',"
|
||||
"'docker_registry'. "
|
||||
"'docker_registry, 'openstack', 'openstack_ca'. "
|
||||
"Default is 'ssl'.")
|
||||
def do_certificate_install(cc, args):
|
||||
"""Install certificate."""
|
||||
|
|
|
@ -269,6 +269,8 @@ class CertificateController(rest.RestController):
|
|||
murano: install certificate for rabbit-murano
|
||||
murano_ca: install ca certificate for rabbit-murano
|
||||
docker_registry: install certificate for docker registry
|
||||
openstack: install certificate for openstack
|
||||
openstack_ca: install ca certificate for openstack
|
||||
"""
|
||||
|
||||
log_start = cutils.timestamped("certificate_do_post_start")
|
||||
|
@ -306,6 +308,16 @@ class CertificateController(rest.RestController):
|
|||
LOG.info(msg)
|
||||
return dict(success="", error=msg)
|
||||
|
||||
if mode.startswith(constants.CERT_MODE_OPENSTACK):
|
||||
try:
|
||||
pecan.request.dbapi.certificate_get_by_certtype(
|
||||
constants.CERT_MODE_SSL)
|
||||
except exception.CertificateTypeNotFound:
|
||||
msg = "No openstack certificates have been added, " \
|
||||
"platform SSL certificate is not installed."
|
||||
LOG.info(msg)
|
||||
return dict(success="", error=msg)
|
||||
|
||||
if not fileitem.filename:
|
||||
return dict(success="", error="Error: No file uploaded")
|
||||
try:
|
||||
|
|
|
@ -1348,18 +1348,35 @@ SSL_CERT_CA_DIR = "/etc/ssl/certs/"
|
|||
SSL_CERT_CA_FILE = os.path.join(SSL_CERT_CA_DIR, CERT_CA_FILE)
|
||||
SSL_CERT_CA_FILE_SHARED = os.path.join(tsc.CONFIG_PATH, CERT_CA_FILE)
|
||||
|
||||
CERT_OPENSTACK_DIR = "/etc/ssl/private/openstack"
|
||||
CERT_OPENSTACK_SHARED_DIR = os.path.join(tsc.CONFIG_PATH, 'openstack')
|
||||
OPENSTACK_CERT_FILE = os.path.join(CERT_OPENSTACK_DIR, CERT_FILE)
|
||||
OPENSTACK_CERT_KEY_FILE = os.path.join(CERT_OPENSTACK_DIR, CERT_KEY_FILE)
|
||||
OPENSTACK_CERT_CA_FILE = os.path.join(CERT_OPENSTACK_DIR, CERT_CA_FILE)
|
||||
OPENSTACK_CERT_FILE_SHARED = os.path.join(CERT_OPENSTACK_SHARED_DIR,
|
||||
CERT_FILE)
|
||||
OPENSTACK_CERT_KEY_FILE_SHARED = os.path.join(CERT_OPENSTACK_SHARED_DIR,
|
||||
CERT_KEY_FILE)
|
||||
OPENSTACK_CERT_CA_FILE_SHARED = os.path.join(CERT_OPENSTACK_SHARED_DIR,
|
||||
CERT_CA_FILE)
|
||||
|
||||
CERT_MODE_SSL = 'ssl'
|
||||
CERT_MODE_SSL_CA = 'ssl_ca'
|
||||
CERT_MODE_TPM = 'tpm_mode'
|
||||
CERT_MODE_MURANO = 'murano'
|
||||
CERT_MODE_MURANO_CA = 'murano_ca'
|
||||
CERT_MODE_DOCKER_REGISTRY = 'docker_registry'
|
||||
CERT_MODE_OPENSTACK = 'openstack'
|
||||
CERT_MODE_OPENSTACK_CA = 'openstack_ca'
|
||||
CERT_MODES_SUPPORTED = [CERT_MODE_SSL,
|
||||
CERT_MODE_SSL_CA,
|
||||
CERT_MODE_TPM,
|
||||
CERT_MODE_MURANO,
|
||||
CERT_MODE_MURANO_CA,
|
||||
CERT_MODE_DOCKER_REGISTRY]
|
||||
CERT_MODE_DOCKER_REGISTRY,
|
||||
CERT_MODE_OPENSTACK,
|
||||
CERT_MODE_OPENSTACK_CA,
|
||||
]
|
||||
|
||||
# CONFIG file permissions
|
||||
CONFIG_FILE_PERMISSION_ROOT_READ_ONLY = 0o400
|
||||
|
|
|
@ -5456,9 +5456,7 @@ class ConductorManager(service.PeriodicService):
|
|||
"personalities": personalities,
|
||||
"classes": ['platform::haproxy::runtime',
|
||||
'openstack::keystone::endpoint::runtime',
|
||||
'openstack::horizon::runtime',
|
||||
'openstack::nova::api::runtime',
|
||||
'openstack::heat::engine::runtime']
|
||||
'openstack::horizon::runtime']
|
||||
}
|
||||
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
|
@ -10204,8 +10202,9 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
certificates = self.dbapi.certificate_get_list()
|
||||
for certificate in certificates:
|
||||
if certificate.certtype in [
|
||||
constants.CERT_MODE_SSL, constants.CERT_MODE_TPM]:
|
||||
if certificate.certtype in [constants.CERT_MODE_SSL,
|
||||
constants.CERT_MODE_TPM,
|
||||
constants.CERT_MODE_OPENSTACK]:
|
||||
self.dbapi.certificate_destroy(certificate.uuid)
|
||||
|
||||
personalities = [constants.CONTROLLER]
|
||||
|
@ -10275,6 +10274,7 @@ class ConductorManager(service.PeriodicService):
|
|||
constants.CERT_MODE_TPM,
|
||||
constants.CERT_MODE_MURANO,
|
||||
constants.CERT_MODE_DOCKER_REGISTRY,
|
||||
constants.CERT_MODE_OPENSTACK,
|
||||
]:
|
||||
private_mode = True
|
||||
|
||||
|
@ -10576,6 +10576,73 @@ class ConductorManager(service.PeriodicService):
|
|||
'permissions': constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY,
|
||||
}
|
||||
self._config_update_file(context, config_uuid, config_dict)
|
||||
elif mode == constants.CERT_MODE_OPENSTACK:
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
key_path = constants.OPENSTACK_CERT_KEY_FILE
|
||||
cert_path = constants.OPENSTACK_CERT_FILE
|
||||
config_dict = {
|
||||
'personalities': personalities,
|
||||
'file_names': [key_path, cert_path],
|
||||
'file_content': {key_path: private_bytes,
|
||||
cert_path: public_bytes},
|
||||
'nobackup': True,
|
||||
'permissions': constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY,
|
||||
}
|
||||
self._config_update_file(context, config_uuid, config_dict)
|
||||
|
||||
if not os.path.exists(constants.CERT_OPENSTACK_SHARED_DIR):
|
||||
os.makedirs(constants.CERT_OPENSTACK_SHARED_DIR)
|
||||
# copy the certificate to shared directory
|
||||
with os.fdopen(os.open(constants.OPENSTACK_CERT_FILE_SHARED,
|
||||
os.O_CREAT | os.O_WRONLY,
|
||||
constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY),
|
||||
'wb') as f:
|
||||
f.write(public_bytes)
|
||||
with os.fdopen(os.open(constants.OPENSTACK_CERT_KEY_FILE_SHARED,
|
||||
os.O_CREAT | os.O_WRONLY,
|
||||
constants.CONFIG_FILE_PERMISSION_ROOT_READ_ONLY),
|
||||
'wb') as f:
|
||||
f.write(private_bytes)
|
||||
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
config_dict = {
|
||||
"personalities": personalities,
|
||||
"classes": ['openstack::keystone::endpoint::runtime',
|
||||
'openstack::horizon::runtime']
|
||||
}
|
||||
self._config_apply_runtime_manifest(context,
|
||||
config_uuid,
|
||||
config_dict)
|
||||
|
||||
self._remove_certificate_file(mode, certificate_file)
|
||||
|
||||
elif mode == constants.CERT_MODE_OPENSTACK_CA:
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
file_content = public_bytes
|
||||
config_dict = {
|
||||
'personalities': personalities,
|
||||
'file_names': [constants.OPENSTACK_CERT_CA_FILE],
|
||||
'file_content': file_content,
|
||||
'permissions': constants.CONFIG_FILE_PERMISSION_DEFAULT,
|
||||
}
|
||||
self._config_update_file(context, config_uuid, config_dict)
|
||||
|
||||
# copy the certificate to shared directory
|
||||
with os.fdopen(os.open(constants.OPENSTACK_CERT_CA_FILE_SHARED,
|
||||
os.O_CREAT | os.O_WRONLY,
|
||||
constants.CONFIG_FILE_PERMISSION_DEFAULT),
|
||||
'wb') as f:
|
||||
f.write(file_content)
|
||||
|
||||
config_uuid = self._config_update_hosts(context, personalities)
|
||||
config_dict = {
|
||||
"personalities": personalities,
|
||||
"classes": ['openstack::keystone::endpoint::runtime',
|
||||
'openstack::horizon::runtime']
|
||||
}
|
||||
self._config_apply_runtime_manifest(context,
|
||||
config_uuid,
|
||||
config_dict)
|
||||
else:
|
||||
msg = "config_certificate unexpected mode=%s" % mode
|
||||
LOG.warn(msg)
|
||||
|
|
|
@ -90,6 +90,8 @@ class GlanceHelm(openstack.OpenstackBaseHelm):
|
|||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
constants.HELM_CHART_GLANCE),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
},
|
||||
'identity': {
|
||||
'auth': self._get_endpoints_identity_overrides(
|
||||
|
|
|
@ -31,7 +31,12 @@ class HorizonHelm(openstack.OpenstackBaseHelm):
|
|||
}
|
||||
}
|
||||
},
|
||||
'endpoints': self._get_endpoints_overrides()
|
||||
'endpoints': self._get_endpoints_overrides(),
|
||||
'network': {
|
||||
'node_port': {
|
||||
'enabled': self._get_network_node_port_overrides()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +54,8 @@ class HorizonHelm(openstack.OpenstackBaseHelm):
|
|||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
constants.HELM_CHART_HORIZON),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
'oslo_db': {
|
||||
'auth': self._get_endpoints_oslo_db_overrides(
|
||||
|
@ -134,3 +141,15 @@ class HorizonHelm(openstack.OpenstackBaseHelm):
|
|||
return False
|
||||
else:
|
||||
return super(HorizonHelm, self)._region_config()
|
||||
|
||||
def _get_network_node_port_overrides(self):
|
||||
# If openstack endpoint FQDN is configured, disable node_port 31000
|
||||
# which will enable the Ingress for the horizon service
|
||||
endpoint_fqdn = self._get_service_parameter(
|
||||
constants.SERVICE_TYPE_OPENSTACK,
|
||||
constants.SERVICE_PARAM_SECTION_OPENSTACK_HELM,
|
||||
constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN)
|
||||
if endpoint_fqdn:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
|
|
@ -248,6 +248,8 @@ class KeystoneHelm(openstack.OpenstackBaseHelm):
|
|||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
self.SERVICE_NAME),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
'oslo_db': {
|
||||
'auth': self._get_endpoints_oslo_db_overrides(
|
||||
|
|
|
@ -388,6 +388,8 @@ class NeutronHelm(openstack.OpenstackBaseHelm):
|
|||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
self.SERVICE_NAME),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
'oslo_cache': {
|
||||
'auth': {
|
||||
|
|
|
@ -56,6 +56,7 @@ class NovaHelm(openstack.OpenstackBaseHelm):
|
|||
SERVICE_NAME = 'nova'
|
||||
AUTH_USERS = ['nova', 'placement']
|
||||
SERVICE_USERS = ['neutron', 'ironic']
|
||||
NOVNCPROXY_SERVICE_NAME = 'novncproxy'
|
||||
|
||||
def get_overrides(self, namespace=None):
|
||||
|
||||
|
@ -158,6 +159,19 @@ class NovaHelm(openstack.OpenstackBaseHelm):
|
|||
'auth': self._get_endpoints_identity_overrides(
|
||||
self.SERVICE_NAME, self.AUTH_USERS),
|
||||
},
|
||||
'compute': {
|
||||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(self.SERVICE_NAME),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
'compute_novnc_proxy': {
|
||||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
self.NOVNCPROXY_SERVICE_NAME),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
'oslo_cache': {
|
||||
'auth': {
|
||||
'memcache_secret_key':
|
||||
|
@ -197,11 +211,14 @@ class NovaHelm(openstack.OpenstackBaseHelm):
|
|||
constants.SERVICE_PARAM_SECTION_OPENSTACK_HELM,
|
||||
constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN)
|
||||
if endpoint_domain is not None:
|
||||
location = "%s.%s" % (constants.HELM_CHART_HORIZON,
|
||||
location = "%s.%s" % (self.NOVNCPROXY_SERVICE_NAME,
|
||||
str(endpoint_domain.value).lower())
|
||||
else:
|
||||
location = self._get_oam_address()
|
||||
url = "http://%s:6080/vnc_auto.html" % location
|
||||
location = self._get_service_default_dns_name(
|
||||
self.NOVNCPROXY_SERVICE_NAME)
|
||||
|
||||
url = "%s://%s/vnc_auto.html" % (self._get_public_protocol(),
|
||||
location)
|
||||
return url
|
||||
|
||||
def _get_virt_type(self):
|
||||
|
|
|
@ -76,5 +76,7 @@ class NovaApiProxyHelm(openstack.OpenstackBaseHelm):
|
|||
'host_fqdn_override':
|
||||
self._get_endpoints_host_fqdn_overrides(
|
||||
constants.HELM_CHART_NOVA),
|
||||
'port': self._get_endpoints_port_api_public_overrides(),
|
||||
'scheme': self._get_endpoints_scheme_public_overrides(),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
|
||||
import keyring
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from Crypto.PublicKey import RSA
|
||||
|
@ -191,6 +192,27 @@ class OpenstackBaseHelm(base.BaseHelm):
|
|||
})
|
||||
return overrides
|
||||
|
||||
def _get_file_content(self, filename):
|
||||
file_contents = ''
|
||||
with open(filename) as f:
|
||||
file_contents = f.read()
|
||||
return file_contents
|
||||
|
||||
def _get_endpoint_public_tls(self):
|
||||
overrides = {}
|
||||
if (os.path.exists(constants.OPENSTACK_CERT_FILE) and
|
||||
os.path.exists(constants.OPENSTACK_CERT_KEY_FILE)):
|
||||
overrides.update({
|
||||
'crt': self._get_file_content(constants.OPENSTACK_CERT_FILE),
|
||||
'key': self._get_file_content(
|
||||
constants.OPENSTACK_CERT_KEY_FILE),
|
||||
})
|
||||
if os.path.exists(constants.OPENSTACK_CERT_CA_FILE):
|
||||
overrides.update({
|
||||
'ca': self._get_file_content(constants.OPENSTACK_CERT_CA_FILE),
|
||||
})
|
||||
return overrides
|
||||
|
||||
def _get_endpoints_host_fqdn_overrides(self, service_name):
|
||||
overrides = {'public': {}}
|
||||
endpoint_domain = self._get_service_parameter(
|
||||
|
@ -201,6 +223,38 @@ class OpenstackBaseHelm(base.BaseHelm):
|
|||
overrides['public'].update({
|
||||
'host': service_name + '.' + str(endpoint_domain.value).lower()
|
||||
})
|
||||
|
||||
# Get TLS certificate files if installed
|
||||
cert = None
|
||||
try:
|
||||
cert = self.dbapi.certificate_get_by_certtype(
|
||||
constants.CERT_MODE_OPENSTACK)
|
||||
except exception.CertificateTypeNotFound:
|
||||
pass
|
||||
if cert is not None:
|
||||
tls_overrides = self._get_endpoint_public_tls()
|
||||
if tls_overrides:
|
||||
overrides['public'].update({
|
||||
'tls': tls_overrides
|
||||
})
|
||||
return overrides
|
||||
|
||||
def _get_endpoints_scheme_public_overrides(self):
|
||||
overrides = {}
|
||||
if self._https_enabled():
|
||||
overrides = {
|
||||
'public': 'https'
|
||||
}
|
||||
return overrides
|
||||
|
||||
def _get_endpoints_port_api_public_overrides(self):
|
||||
overrides = {}
|
||||
if self._https_enabled():
|
||||
overrides = {
|
||||
'api': {
|
||||
'public': 443
|
||||
}
|
||||
}
|
||||
return overrides
|
||||
|
||||
def _get_endpoints_oslo_db_overrides(self, service_name, users):
|
||||
|
@ -335,3 +389,10 @@ class OpenstackBaseHelm(base.BaseHelm):
|
|||
}
|
||||
}
|
||||
return override
|
||||
|
||||
def _get_public_protocol(self):
|
||||
return 'https' if self._https_enabled() else 'http'
|
||||
|
||||
def _get_service_default_dns_name(self, service):
|
||||
return "{}.{}.svc.{}".format(service, common.HELM_NS_OPENSTACK,
|
||||
constants.DEFAULT_DNS_SERVICE_DOMAIN)
|
||||
|
|
Loading…
Reference in New Issue