Add certificate management support
Certificates for payload traffic is provided through Barbican secrets store and must be uploaded by the end-user. Certificates for authentication between Octavia controllers and its Amphorae instances are issued locally on the Octavia controller. At the time of this writing this is the only supported alternative upstream after the retirement of the Anchor project [0]. Note that the locally generated certificates are not used for any load balancer payload data. 0: https://review.openstack.org/#/c/597022/ Change-Id: I38c3e39de4d4cb173970a615f270839871d13910
This commit is contained in:
parent
0cc41b5dcd
commit
4d834c4d2d
|
@ -0,0 +1,68 @@
|
|||
options:
|
||||
loadbalancer-topology:
|
||||
type: string
|
||||
default: SINGLE
|
||||
description: |
|
||||
Load balancer topology configuration.
|
||||
.
|
||||
Supported values are 'SINGLE' and 'ACTIVE_STANDBY'.
|
||||
lb-mgmt-issuing-cacert:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Certificate Authority Certificate used to issue new certificates stored
|
||||
on the ``Amphora`` load balancer instances. The ``Amphorae`` use them to
|
||||
authenticate themselves to the ``Octavia`` controller services.
|
||||
.
|
||||
Note due to security concerns it is important not use the same CA
|
||||
certificate for both ``lb-mgmt-issuing-cacert`` and
|
||||
``lb-mgmt-controller-cacert`` configuration options. Failing to keep
|
||||
them separate may lead to abuse of certificate data to gain access to
|
||||
other ``Amphora`` instances in the event one of them is compromised.
|
||||
.
|
||||
Note that these certificates are not used for any load balancer payload
|
||||
data.
|
||||
lb-mgmt-issuing-ca-private-key:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Private key for the Certificate Authority set in ``lb-mgmt-issuing-ca``.
|
||||
.
|
||||
Note that these certificates are not used for any load balancer payload
|
||||
data.
|
||||
lb-mgmt-issuing-ca-key-passphrase:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Passphrase for the key set in ``lb-mgmt-ca-private-key``.
|
||||
.
|
||||
NOTE: As of this writing Octavia requires the private key to be protected
|
||||
with a passphrase.
|
||||
.
|
||||
Note that these certificates are not used for any load balancer payload
|
||||
data.
|
||||
lb-mgmt-controller-cacert:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Certificate Authority Certificate installed on ``Amphorae`` with the
|
||||
purpose of the ``Amphora`` agent using it to authenticate connections
|
||||
from ``Octavia`` controller services.
|
||||
.
|
||||
Note due to security concerns it is important not use the same CA
|
||||
certificate for both ``lb-mgmt-issuing-cacert`` and
|
||||
``lb-mgmt-controller-cacert`` configuration options. Failing to keep
|
||||
them separate may lead to abuse of certificate data to gain access to
|
||||
other ``Amphora`` instances in the event one of them is compromised.
|
||||
.
|
||||
Note that these certificates are not used for any load balancer payload
|
||||
data.
|
||||
lb-mgmt-controller-cert:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Certificate used by the ``Octavia`` controller to authenticate itself to
|
||||
its ``Amphorae``.
|
||||
.
|
||||
Note that these certificates are not used for any load balancer payload
|
||||
data.
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import base64
|
||||
import collections
|
||||
import os
|
||||
import subprocess
|
||||
|
@ -22,9 +23,10 @@ import charms_openstack.ip as os_ip
|
|||
|
||||
import charms.leadership as leadership
|
||||
|
||||
import charmhelpers.core.host as ch_host
|
||||
import charmhelpers.core as ch_core
|
||||
|
||||
OCTAVIA_DIR = '/etc/octavia'
|
||||
OCTAVIA_CACERT_DIR = os.path.join(OCTAVIA_DIR, 'certs')
|
||||
OCTAVIA_CONF = os.path.join(OCTAVIA_DIR, 'octavia.conf')
|
||||
OCTAVIA_WEBSERVER_SITE = 'octavia-api'
|
||||
OCTAVIA_WSGI_CONF = '/etc/apache2/sites-available/octavia-api.conf'
|
||||
|
@ -43,6 +45,91 @@ class OctaviaAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters):
|
|||
charm_intance=charm_instance)
|
||||
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def issuing_cacert(cls):
|
||||
"""Get path to certificate provided in ``lb-mgmt-issuing-cacert`` option.
|
||||
|
||||
Side effect of reading this property is that the on-disk certificate
|
||||
data is updated if it has changed.
|
||||
|
||||
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
|
||||
instance. Charm class instance is at cls.charm_instance.
|
||||
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
|
||||
"""
|
||||
config = ch_core.hookenv.config('lb-mgmt-issuing-cacert')
|
||||
if config:
|
||||
return cls.charm_instance.decode_and_write_cert(
|
||||
'issuing_ca.pem',
|
||||
config)
|
||||
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def issuing_ca_private_key(cls):
|
||||
"""Get path to key provided in ``lb-mgmt-issuing-ca-private-key`` option.
|
||||
|
||||
Side effect of reading this property is that the on-disk key
|
||||
data is updated if it has changed.
|
||||
|
||||
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
|
||||
instance. Charm class instance is at cls.charm_instance.
|
||||
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
|
||||
"""
|
||||
config = ch_core.hookenv.config('lb-mgmt-issuing-ca-private-key')
|
||||
if config:
|
||||
return cls.charm_instance.decode_and_write_cert(
|
||||
'issuing_ca_key.pem',
|
||||
config)
|
||||
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def issuing_ca_private_key_passphrase(cls):
|
||||
"""Get value provided in in ``lb-mgmt-issuing-ca-key-passphrase`` option.
|
||||
|
||||
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
|
||||
instance. Charm class instance is at cls.charm_instance.
|
||||
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
|
||||
"""
|
||||
config = ch_core.hookenv.config('lb-mgmt-issuing-ca-key-passphrase')
|
||||
if config:
|
||||
return config
|
||||
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def controller_cacert(cls):
|
||||
"""Get path to certificate provided in ``lb-mgmt-controller-cacert`` opt.
|
||||
|
||||
Side effect of reading this property is that the on-disk certificate
|
||||
data is updated if it has changed.
|
||||
|
||||
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
|
||||
instance. Charm class instance is at cls.charm_instance.
|
||||
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
|
||||
"""
|
||||
config = ch_core.hookenv.config('lb-mgmt-controller-cacert')
|
||||
if config:
|
||||
return cls.charm_instance.decode_and_write_cert(
|
||||
'controller_ca.pem',
|
||||
config)
|
||||
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def controller_cert(cls):
|
||||
"""Get path to certificate provided in ``lb-mgmt-controller-cert`` option.
|
||||
|
||||
Side effect of reading this property is that the on-disk certificate
|
||||
data is updated if it has changed.
|
||||
|
||||
:param cls: charms_openstack.adapters.ConfigurationAdapter derived class
|
||||
instance. Charm class instance is at cls.charm_instance.
|
||||
:type: cls: charms_openstack.adapters.ConfiguartionAdapter
|
||||
"""
|
||||
config = ch_core.hookenv.config('lb-mgmt-controller-cert')
|
||||
if config:
|
||||
return cls.charm_instance.decode_and_write_cert(
|
||||
'controller_cert.pem',
|
||||
config)
|
||||
|
||||
|
||||
class OctaviaCharm(charms_openstack.charm.HAOpenStackCharm):
|
||||
"""Charm class for the Octavia charm."""
|
||||
# layer-openstack-api uses service_type as service name in endpoint catalog
|
||||
|
@ -95,8 +182,27 @@ class OctaviaCharm(charms_openstack.charm.HAOpenStackCharm):
|
|||
if check_enabled != 0:
|
||||
subprocess.check_call(['a2ensite',
|
||||
OCTAVIA_WEBSERVER_SITE])
|
||||
ch_host.service_reload('apache2',
|
||||
restart_on_failure=True)
|
||||
ch_core.host.service_reload('apache2',
|
||||
restart_on_failure=True)
|
||||
|
||||
def decode_and_write_cert(self, filename, encoded_data):
|
||||
"""Write certificate data to disk.
|
||||
|
||||
:param filename: Name of file
|
||||
:type filename: str
|
||||
:param group: Group ownership
|
||||
:type group: str
|
||||
:param encoded_data: Base64 encoded data
|
||||
:type encoded_data: str
|
||||
:returns: Full path to file
|
||||
:rtype: str
|
||||
"""
|
||||
filename = os.path.join(OCTAVIA_CACERT_DIR, filename)
|
||||
ch_core.host.mkdir(OCTAVIA_CACERT_DIR, group=self.group,
|
||||
perms=0o750)
|
||||
ch_core.host.write_file(filename, base64.b64decode(encoded_data),
|
||||
group=self.group, perms=0o440)
|
||||
return filename
|
||||
|
||||
@charms_openstack.adapters.config_property
|
||||
def heartbeat_key(self):
|
||||
|
|
|
@ -7,6 +7,62 @@ heartbeat_key = {{ options.heartbeat_key }}
|
|||
[database]
|
||||
{% include "parts/database" %}
|
||||
|
||||
[controller_worker]
|
||||
{% if options.amp_image_owner_id -%}
|
||||
amp_image_owner_id = {{ options.amp_image_owner_id }}
|
||||
{% endif -%}
|
||||
{% if options.amp_secgroup_list -%}
|
||||
amp_secgroup_list = {{ options.amp_secgroup_list }}
|
||||
{% endif -%}
|
||||
{% if options.amp_flavor_id -%}
|
||||
amp_flavor_id = {{ options.amp_flavor_id }}
|
||||
{% endif -%}
|
||||
{% if options.amp_boot_network_list -%}
|
||||
amp_boot_network_list = {{ options.amp_boot_network_list }}
|
||||
{% endif -%}
|
||||
{% if options.amp_ssh_key_name -%}
|
||||
amp_ssh_key_name = {{ options.amp_ssh_key_name }}
|
||||
{% endif -%}
|
||||
{% if options.amp_image_tag -%}
|
||||
amp_image_tag = {{ options.amp_image_tag }}
|
||||
{% endif -%}
|
||||
amp_active_retries = 180
|
||||
# This certificate is installed on the ``Amphorae`` and used for validating
|
||||
# the authenticity of the ``Octavia`` controller.
|
||||
client_ca = {{ options.controller_cacert }}
|
||||
network_driver = allowed_address_pairs_driver
|
||||
compute_driver = compute_nova_driver
|
||||
amphora_driver = amphora_haproxy_rest_driver
|
||||
loadbalancer_topology = {{ options.loadbalancer_topology }}
|
||||
|
||||
[certificates]
|
||||
# NOTE(fnordahl) certificates for authentication between Octavia controllers
|
||||
# and its Amphorae instances are issued locally on the Octavia controller.
|
||||
#
|
||||
# At the time of this writing this is the only supported alternative upstream
|
||||
# after the retirement of the Anchor project [0].
|
||||
#
|
||||
# Note that these certificates are not used for any load balancer payload data
|
||||
#
|
||||
# 0: https://review.openstack.org/#/c/597022/
|
||||
cert_generator = local_cert_generator
|
||||
# This certificate is used to issue individual certificates for each
|
||||
# ``Amphora`` and to validate their authenticity when they connect to the
|
||||
# ``Octavia`` controller.
|
||||
ca_certificate = {{ options.issuing_cacert }}
|
||||
ca_private_key = {{ options.issuing_ca_private_key }}
|
||||
ca_private_key_passphrase = {{ options.issuing_ca_private_key_passphrase }}
|
||||
|
||||
cert_manager = barbican_cert_manager
|
||||
|
||||
[haproxy_amphora]
|
||||
# This certificate is used by the ``Octavia`` controller to validate the
|
||||
# authenticity of the ``Amphorae`` connecting to it.
|
||||
server_ca = {{ options.issuing_cacert }}
|
||||
# This certificate is used by the ``Octavia`` controller when it takes on the
|
||||
# role as a "client" connecting to the ``Amphorae``.
|
||||
client_cert = {{ options.controller_cert }}
|
||||
|
||||
[service_auth]
|
||||
auth_type = password
|
||||
auth_uri = {{ identity_service.service_protocol }}://{{ identity_service.service_host }}:{{ identity_service.service_port }}
|
||||
|
|
Loading…
Reference in New Issue