octavia/octavia/common/utils.py
Nir Magnezi ae7c87f54a Encrypt certs and keys
Octavia creates certificates and keys to manage encrypted
communication channel to amphorae.
When debug is enabled, the python taskflow module will log
all the information we provide to tasks (and sub-flows)
when we create amphorae or handle with anything related to
certificates and keys management (rotations, etc).

There are ways to tell taskflow to exclude specific things
from being logged (e.g., I136081045787c1bbe3ee846d5845a34201c57864).
While this handles some information in specific flows from being
logged, it is susceptive to code changes.

To avoid an everlasting whack-a-mole game, this patch will merely
encrypt sensitive information so we can safely log it and decrypts
it only when we need to use it.

Change-Id: I06d329ca53bc36bd27f7870ae7c7ca0cf18575b2
2019-02-24 15:41:20 +02:00

131 lines
4.0 KiB
Python

# Copyright 2011, VMware, Inc., 2014 A10 Networks
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Borrowed from nova code base, more utilities will be added/borrowed as and
# when needed.
"""Utilities and helper functions."""
import base64
import hashlib
import socket
import netaddr
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
import six
from stevedore import driver as stevedore_driver
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
def get_hostname():
return socket.gethostname()
def base64_sha1_string(string_to_hash):
"""Get a b64-encoded sha1 hash of a string. Not intended to be secure!"""
# TODO(rm_work): applying nosec here because this is not intended to be
# secure, it's just a way to get a consistent ID. Changing this would
# break backwards compatibility with existing loadbalancers.
hash_str = hashlib.sha1(string_to_hash.encode('utf-8')).digest() # nosec
b64_str = base64.b64encode(hash_str, str.encode('_-', 'ascii'))
return b64_str.decode('UTF-8')
def get_network_driver():
CONF.import_group('controller_worker', 'octavia.common.config')
network_driver = stevedore_driver.DriverManager(
namespace='octavia.network.drivers',
name=CONF.controller_worker.network_driver,
invoke_on_load=True
).driver
return network_driver
def is_ipv6(ip_address):
"""Check if ip address is IPv6 address."""
ip = netaddr.IPAddress(ip_address)
return ip.version == 6
def is_ipv6_lla(ip_address):
"""Check if ip address is IPv6 link local address."""
ip = netaddr.IPAddress(ip_address)
return ip.version == 6 and ip.is_link_local()
def ip_port_str(ip_address, port):
"""Return IP port as string representation depending on address family."""
ip = netaddr.IPAddress(ip_address)
if ip.version == 4:
return "{ip}:{port}".format(ip=ip, port=port)
return "[{ip}]:{port}".format(ip=ip, port=port)
def netmask_to_prefix(netmask):
return netaddr.IPAddress(netmask).netmask_bits()
def ip_netmask_to_cidr(ip, netmask):
net = netaddr.IPNetwork("0.0.0.0/0")
if ip and netmask:
net = netaddr.IPNetwork(
"{ip}/{netmask}".format(ip=ip, netmask=netmask)
)
return "{ip}/{netmask}".format(ip=net.network, netmask=net.prefixlen)
def get_six_compatible_value(value, six_type=six.string_types):
if six.PY3 and isinstance(value, six_type):
value = value.encode('utf-8')
return value
def get_six_compatible_server_certs_key_passphrase():
key = CONF.certificates.server_certs_key_passphrase
if six.PY3 and isinstance(key, six.string_types):
key = key.encode('utf-8')
return base64.urlsafe_b64encode(key)
class exception_logger(object):
"""Wrap a function and log raised exception
:param logger: the logger to log the exception default is LOG.exception
:returns: origin value if no exception raised; re-raise the exception if
any occurred
"""
def __init__(self, logger=None):
self.logger = logger
def __call__(self, func):
if self.logger is None:
_LOG = logging.getLogger(func.__module__)
self.logger = _LOG.exception
def call(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
with excutils.save_and_reraise_exception():
self.logger(e)
return call