diff --git a/swift/common/middleware/crypto/kmip_keymaster.py b/swift/common/middleware/crypto/kmip_keymaster.py index 11566a1fb4..5d3d204bfb 100644 --- a/swift/common/middleware/crypto/kmip_keymaster.py +++ b/swift/common/middleware/crypto/kmip_keymaster.py @@ -17,6 +17,7 @@ import logging import os from swift.common.middleware.crypto import keymaster +from swift.common.utils import LogLevelFilter from kmip.pie.client import ProxyKmipClient @@ -122,6 +123,18 @@ class KmipKeyMaster(keymaster.BaseKeyMaster): for handler in self.logger.logger.handlers: kmip_logger.addHandler(handler) + debug_filter = LogLevelFilter(logging.DEBUG) + for name in ( + # The kmip_protocol logger includes hex-encoded data off the + # wire, which may include key material!! We *NEVER* want that + # enabled. + 'kmip.services.server.kmip_protocol', + # The config_helper logger includes any password that may be + # provided, which doesn't seem great either. + 'kmip.core.config_helper', + ): + logging.getLogger(name).addFilter(debug_filter) + multikey_opts = self._load_multikey_opts(conf, 'key_id') if not multikey_opts: raise ValueError('key_id option is required') diff --git a/swift/common/utils.py b/swift/common/utils.py index fedad1cd8a..57b219c36a 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -2088,6 +2088,25 @@ class SwiftLogFormatter(logging.Formatter): return msg +class LogLevelFilter(object): + """ + Drop messages for the logger based on level. + + This is useful when dependencies log too much information. + + :param level: All messages at or below this level are dropped + (DEBUG < INFO < WARN < ERROR < CRITICAL|FATAL) + Default: DEBUG + """ + def __init__(self, level=logging.DEBUG): + self.level = level + + def filter(self, record): + if record.levelno <= self.level: + return 0 + return 1 + + def get_logger(conf, name=None, log_to_console=False, log_route=None, fmt="%(server)s: %(message)s"): """ diff --git a/test/unit/common/middleware/crypto/test_kmip_keymaster.py b/test/unit/common/middleware/crypto/test_kmip_keymaster.py index 3eb50e7e9d..bbe167b823 100644 --- a/test/unit/common/middleware/crypto/test_kmip_keymaster.py +++ b/test/unit/common/middleware/crypto/test_kmip_keymaster.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import logging import mock import os import unittest @@ -62,6 +63,15 @@ def create_mock_client(secrets, calls): return mock_client +class InMemoryHandler(logging.Handler): + def __init__(self): + self.messages = [] + super(InMemoryHandler, self).__init__() + + def handle(self, record): + self.messages.append(record.msg) + + class TestKmipKeymaster(unittest.TestCase): def setUp(self): @@ -269,3 +279,38 @@ class TestKmipKeymaster(unittest.TestCase): with self.assertRaises(ValueError) as cm: KmipKeyMaster(None, conf) self.assertIn('key_id option is required', str(cm.exception)) + + def test_logger_manipulations(self): + root_logger = logging.getLogger() + old_level = root_logger.getEffectiveLevel() + handler = InMemoryHandler() + try: + root_logger.setLevel(logging.DEBUG) + root_logger.addHandler(handler) + + conf = {'__file__': '/etc/swift/proxy-server.conf', + '__name__': 'kmip_keymaster'} + with self.assertRaises(ValueError): + # missing key_id, as above, but that's not the interesting bit + KmipKeyMaster(None, conf) + + self.assertEqual(handler.messages, []) + + logger = logging.getLogger('kmip.services.server.kmip_protocol') + logger.debug('Something secret!') + logger.info('Something useful') + self.assertNotIn('Something secret!', handler.messages) + self.assertIn('Something useful', handler.messages) + + logger = logging.getLogger('kmip.core.config_helper') + logger.debug('Also secret') + logger.warning('Also useful') + self.assertNotIn('Also secret', handler.messages) + self.assertIn('Also useful', handler.messages) + + logger = logging.getLogger('kmip') + logger.debug('Boring, but not secret') + self.assertIn('Boring, but not secret', handler.messages) + finally: + root_logger.setLevel(old_level) + root_logger.removeHandler(handler)