Opt-out certain Keystone Notifications

This patch will allow certain notifications for events in
Keystone to be opted out. Opting out may be a desired way of
doing this since most keystone deployers will likely like
to by default have all audit traces.

Change-Id: I86caf6e5f25cdd76121881813167c2144bf1d051
Closes-Bug: 1519210
This commit is contained in:
Fernando Diaz 2015-12-04 22:23:15 -06:00 committed by Steve Martinelli
parent 6fe74951ac
commit 255685877e
4 changed files with 147 additions and 1 deletions

View File

@ -28,7 +28,7 @@ The supported operations between the two types of notification formats are
documented below. documented below.
Common Notification Structure Common Notification Structure
============================== =============================
Notifications generated by Keystone are generated in JSON format. An external Notifications generated by Keystone are generated in JSON format. An external
application can format them into ATOM format and publish them as a feed. application can format them into ATOM format and publish them as a feed.
@ -414,3 +414,26 @@ ensures this has an immediate impact on the accessibility of the project's
resources by revoking tokens with authorization on the project, but should resources by revoking tokens with authorization on the project, but should
**not** have a direct impact on the projects resources (in other words, virtual **not** have a direct impact on the projects resources (in other words, virtual
machines should **not** be deleted). machines should **not** be deleted).
Opting out of certain notifications
===================================
There are many notifications that Keystone emits and some deployers may only
care about certain events. In Keystone there is a way to opt-out of certain
notifications. In ``/etc/keystone/keystone.conf`` you can set ``opt_out`` to
the event you wish to opt-out of. It is possible to opt-out of multiple events.
Example:
.. code-block:: ini
[DEFAULT]
notification_opt_out = identity.user.created
notification_opt_out = identity.role_assignment.created
notification_opt_out = identity.authenticate.pending
This will opt-out notifications for user creation, role assignment creation and
successful authentications. For a list of event types that can be used, refer
to: `Telemetry Measurements`_.
.. _Telemetry Measurements: http://docs.openstack.org/admin-guide-cloud/telemetry-measurements.html#openstack-identity

View File

@ -45,6 +45,14 @@ notifier_opts = [
'the resource being operated on. A "cadf" notification ' 'the resource being operated on. A "cadf" notification '
'has the same information, as well as information about ' 'has the same information, as well as information about '
'the initiator of the event.'), 'the initiator of the event.'),
cfg.MultiStrOpt('notification_opt_out', default=[],
help='Define the notification options to opt-out from. '
'The value expected is: '
'identity.<resource_type>.<operation>. This field '
'can be set multiple times in order to add more '
'notifications to opt-out from. For example:\n '
'notification_opt_out=identity.user.created\n '
'notification_opt_out=identity.authenticate.success'),
] ]
config_section = None config_section = None
@ -470,6 +478,8 @@ def _send_notification(operation, resource_type, resource_id, public=True):
'service': SERVICE, 'service': SERVICE,
'resource_type': resource_type, 'resource_type': resource_type,
'operation': operation} 'operation': operation}
if _check_notification_opt_out(event_type, outcome=None):
return
try: try:
notifier.info(context, event_type, payload) notifier.info(context, event_type, payload)
except Exception: except Exception:
@ -716,6 +726,9 @@ def _send_audit_notification(action, initiator, outcome, target,
key-value pairs to the CADF event. key-value pairs to the CADF event.
""" """
if _check_notification_opt_out(event_type, outcome):
return
event = eventfactory.EventFactory().new_event( event = eventfactory.EventFactory().new_event(
eventType=cadftype.EVENTTYPE_ACTIVITY, eventType=cadftype.EVENTTYPE_ACTIVITY,
outcome=outcome, outcome=outcome,
@ -742,6 +755,33 @@ def _send_audit_notification(action, initiator, outcome, target,
{'action': action, 'event_type': event_type}) {'action': action, 'event_type': event_type})
def _check_notification_opt_out(event_type, outcome):
"""Check if a particular event_type has been opted-out of.
This method checks to see if an event should be sent to the messaging
service. Any event specified in the opt-out list will not be transmitted.
:param event_type: This is the meter name that Ceilometer uses to poll
events. For example: identity.user.created, or
identity.authenticate.success, or identity.role_assignment.created
:param outcome: The CADF outcome (taxonomy.OUTCOME_PENDING,
taxonomy.OUTCOME_SUCCESS, taxonomy.OUTCOME_FAILURE)
"""
# NOTE(stevemar): Special handling for authenticate, we look at the outcome
# as well when evaluating. For authN events, event_type is just
# idenitity.authenticate, which isn't fine enough to provide any opt-out
# value, so we attach the outcome to re-create the meter name used in
# ceilometer.
if 'authenticate' in event_type:
event_type = event_type + "." + outcome
if event_type in CONF.notification_opt_out:
return True
return False
emit_event = CadfNotificationWrapper emit_event = CadfNotificationWrapper

View File

@ -201,6 +201,82 @@ class NotificationsTestCase(unit.BaseTestCase):
resource) resource)
mocked.assert_called_once_with(*expected_args) mocked.assert_called_once_with(*expected_args)
def test_send_notification_with_opt_out(self):
"""Test the private method _send_notification with opt-out.
Test that _send_notification does not notify when a valid
notification_opt_out configuration is provided.
"""
resource = uuid.uuid4().hex
resource_type = EXP_RESOURCE_TYPE
operation = CREATED_OPERATION
event_type = 'identity.%s.created' % resource_type
# NOTE(diazjf): Here we add notification_opt_out to the
# configuration so that we should return before _get_notifer is
# called. This is because we are opting out notifications for the
# passed resource_type and operation.
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=event_type)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_notification(operation, resource_type,
resource)
mocked.assert_not_called()
def test_send_audit_notification_with_opt_out(self):
"""Test the private method _send_audit_notification with opt-out.
Test that _send_audit_notification does not notify when a valid
notification_opt_out configuration is provided.
"""
resource_type = EXP_RESOURCE_TYPE
action = CREATED_OPERATION + '.' + resource_type
initiator = mock
target = mock
outcome = 'success'
event_type = 'identity.%s.created' % resource_type
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=event_type)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_audit_notification(action,
initiator,
outcome,
target,
event_type)
mocked.assert_not_called()
def test_opt_out_authenticate_event(self):
"""Test that authenticate events are successfully opted out."""
resource_type = EXP_RESOURCE_TYPE
action = CREATED_OPERATION + '.' + resource_type
initiator = mock
target = mock
outcome = 'success'
event_type = 'identity.authenticate'
meter_name = '%s.%s' % (event_type, outcome)
conf = self.useFixture(config_fixture.Config(CONF))
conf.config(notification_opt_out=meter_name)
with mock.patch.object(notifications._get_notifier(),
'_notify') as mocked:
notifications._send_audit_notification(action,
initiator,
outcome,
target,
event_type)
mocked.assert_not_called()
class BaseNotificationTest(test_v3.RestfulTestCase): class BaseNotificationTest(test_v3.RestfulTestCase):

View File

@ -0,0 +1,7 @@
---
features:
- >
[`bug 1519210 <https://bugs.launchpad.net/keystone/+bug/1519210>`_]
A user may now opt-out of notifications by specifying a list of
`event_types` in the ``notification_opt_out`` option in `keystone.conf`.
These events are never sent to a messaging service.