[openstack-nova/f20] Add RBAC policy for ec2 API security groups calls

Vladan Popovic vpopovic at fedoraproject.org
Mon Jun 30 15:10:18 UTC 2014


commit ecc8260e4eb4fb0656fe3c52001d7e9220ae2d69
Author: Vladan Popovic <vpopovic at redhat.com>
Date:   Mon Jun 30 16:22:49 2014 +0200

    Add RBAC policy for ec2 API security groups calls
    
    Changelog:
    - Add RBAC policy for ec2 API security groups calls
    - Move notification point to a better place
    - notify calling process we are ready to serve
    
    Resolves: CVE-2014-0167

 ...ify-calling-process-we-are-ready-to-serve.patch |  168 ++++++++++++++++++++
 ...Move-notification-point-to-a-better-place.patch |   50 ++++++
 ...-policy-for-ec2-API-security-groups-calls.patch |  146 +++++++++++++++++
 openstack-nova.spec                                |   13 ++-
 4 files changed, 376 insertions(+), 1 deletions(-)
---
diff --git a/0003-notify-calling-process-we-are-ready-to-serve.patch b/0003-notify-calling-process-we-are-ready-to-serve.patch
new file mode 100644
index 0000000..82eeb3d
--- /dev/null
+++ b/0003-notify-calling-process-we-are-ready-to-serve.patch
@@ -0,0 +1,168 @@
+From 1dee5040c80887761ae84e791b35cbdc42bbd8cd Mon Sep 17 00:00:00 2001
+From: Alan Pevec <apevec at redhat.com>
+Date: Tue, 11 Feb 2014 22:36:00 +0100
+Subject: [PATCH] notify calling process we are ready to serve
+
+Systemd notification should be sent in-process, otherwise systemd might
+miss the subprocess sending notification.
+See systemd bug https://bugzilla.redhat.com/show_bug.cgi?id=820448
+
+Taken from keystone project commit
+abc06716d027d68f0da3b0f559fa7c85a21804d5
+
+Improvements from Keystone version:
+
+    * add unset_environment parameter
+    New parameter unset_environment was added to sd_notify
+    http://www.freedesktop.org/software/systemd/man/sd_notify.html
+    to ensure service readiness is sent only once.
+
+    * add onready() method to simulate systemd environment
+    For testing purposes and optional use with SysV initscripts.
+
+    * unit test added
+
+    * docstrings for notification methods
+
+Patch includes deployment in openstack.common.service.
+It does not have an effect when running the service outside
+the systemd environment.
+
+Implements: blueprint service-readiness
+Change-Id: I80f325c9be9c171c2dc8d5526570bf64f0f87c78
+---
+ nova/openstack/common/service.py |   2 +
+ nova/openstack/common/systemd.py | 104 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 106 insertions(+)
+ create mode 100644 nova/openstack/common/systemd.py
+
+diff --git a/nova/openstack/common/service.py b/nova/openstack/common/service.py
+index a1f4309..1ce95a0 100644
+--- a/nova/openstack/common/service.py
++++ b/nova/openstack/common/service.py
+@@ -34,6 +34,7 @@ from nova.openstack.common import eventlet_backdoor
+ from nova.openstack.common.gettextutils import _
+ from nova.openstack.common import importutils
+ from nova.openstack.common import log as logging
++from nova.openstack.common import systemd
+ from nova.openstack.common import threadgroup
+ 
+ 
+@@ -63,6 +64,7 @@ class Launcher(object):
+ 
+         """
+         service.start()
++        systemd.notify_once()
+         service.wait()
+ 
+     def launch_service(self, service):
+diff --git a/nova/openstack/common/systemd.py b/nova/openstack/common/systemd.py
+new file mode 100644
+index 0000000..4fa0c62
+--- /dev/null
++++ b/nova/openstack/common/systemd.py
+@@ -0,0 +1,104 @@
++# Copyright 2012-2014 Red Hat, Inc.
++#
++#    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.
++
++"""
++Helper module for systemd service readiness notification.
++"""
++
++import os
++import socket
++import sys
++
++from nova.openstack.common import log as logging
++
++
++LOG = logging.getLogger(__name__)
++
++
++def _abstractify(socket_name):
++    if socket_name.startswith('@'):
++        # abstract namespace socket
++        socket_name = '\0%s' % socket_name[1:]
++    return socket_name
++
++
++def _sd_notify(unset_env, msg):
++    notify_socket = os.getenv('NOTIFY_SOCKET')
++    if notify_socket:
++        sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
++        try:
++            sock.connect(_abstractify(notify_socket))
++            sock.sendall(msg)
++            if unset_env:
++                del os.environ['NOTIFY_SOCKET']
++        except EnvironmentError:
++            LOG.debug("Systemd notification failed", exc_info=True)
++        finally:
++            sock.close()
++
++
++def notify():
++    """Send notification to Systemd that service is ready.
++    For details see
++      http://www.freedesktop.org/software/systemd/man/sd_notify.html
++    """
++    _sd_notify(False, 'READY=1')
++
++
++def notify_once():
++    """Send notification once to Systemd that service is ready.
++    Systemd sets NOTIFY_SOCKET environment variable with the name of the
++    socket listening for notifications from services.
++    This method removes the NOTIFY_SOCKET environment variable to ensure
++    notification is sent only once.
++    """
++    _sd_notify(True, 'READY=1')
++
++
++def onready(notify_socket, timeout):
++    """Wait for systemd style notification on the socket.
++
++    :param notify_socket: local socket address
++    :type notify_socket:  string
++    :param timeout:       socket timeout
++    :type timeout:        float
++    :returns:             0 service ready
++                          1 service not ready
++                          2 timeout occured
++    """
++    sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
++    sock.settimeout(timeout)
++    sock.bind(_abstractify(notify_socket))
++    try:
++        msg = sock.recv(512)
++    except socket.timeout:
++        return 2
++    finally:
++        sock.close()
++    if 'READY=1' in msg:
++        return 0
++    else:
++        return 1
++
++
++if __name__ == '__main__':
++    # simple CLI for testing
++    if len(sys.argv) == 1:
++        notify()
++    elif len(sys.argv) >= 2:
++        timeout = float(sys.argv[1])
++        notify_socket = os.getenv('NOTIFY_SOCKET')
++        if notify_socket:
++            retval = onready(notify_socket, timeout)
++            sys.exit(retval)
diff --git a/0004-Move-notification-point-to-a-better-place.patch b/0004-Move-notification-point-to-a-better-place.patch
new file mode 100644
index 0000000..fc4ff08
--- /dev/null
+++ b/0004-Move-notification-point-to-a-better-place.patch
@@ -0,0 +1,50 @@
+From 1c831b971bc3f33a533e875379b0148265c6adab Mon Sep 17 00:00:00 2001
+From: Alan Pevec <apevec at redhat.com>
+Date: Mon, 14 Apr 2014 18:11:04 +0200
+Subject: [PATCH] Move notification point to a better place
+
+Follow-up for I80f325c9be9c171c2dc8d5526570bf64f0f87c78
+"notify calling process we are ready to serve"
+
+Xavier Queralt found issue with sending readiness notification from inside
+run_service: it returns premature OK in case of multiple service endpoints
+in one systemd service like nova-api which by default provides osapi, ec2 and
+metadata services.
+
+Instead, send readiness notification before entering wait loop for each
+Launcher type.
+
+Change-Id: I69bf10f353f5fecaaf89e537c2d3c46b73e39d36
+Implements: blueprint service-readiness
+---
+ nova/openstack/common/service.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/nova/openstack/common/service.py b/nova/openstack/common/service.py
+index 1ce95a0..fc86193 100644
+--- a/nova/openstack/common/service.py
++++ b/nova/openstack/common/service.py
+@@ -64,7 +64,6 @@ class Launcher(object):
+ 
+         """
+         service.start()
+-        systemd.notify_once()
+         service.wait()
+ 
+     def launch_service(self, service):
+@@ -112,6 +111,7 @@ class ServiceLauncher(Launcher):
+         signal.signal(signal.SIGTERM, self._handle_signal)
+         signal.signal(signal.SIGINT, self._handle_signal)
+ 
++        systemd.notify_once()
+         LOG.debug(_('Full set of CONF:'))
+         CONF.log_opt_values(LOG, std_logging.DEBUG)
+ 
+@@ -275,6 +275,7 @@ class ProcessLauncher(object):
+     def wait(self):
+         """Loop waiting on children to die and respawning as necessary"""
+ 
++        systemd.notify_once()
+         LOG.debug(_('Full set of CONF:'))
+         CONF.log_opt_values(LOG, std_logging.DEBUG)
+ 
diff --git a/0005-Add-RBAC-policy-for-ec2-API-security-groups-calls.patch b/0005-Add-RBAC-policy-for-ec2-API-security-groups-calls.patch
new file mode 100644
index 0000000..aaa8d24
--- /dev/null
+++ b/0005-Add-RBAC-policy-for-ec2-API-security-groups-calls.patch
@@ -0,0 +1,146 @@
+From e8d047beb90a22decdeff3dcf51e39800e4f111d Mon Sep 17 00:00:00 2001
+From: Andrew Laski <andrew.laski at rackspace.com>
+Date: Wed, 9 Apr 2014 09:27:44 -0400
+Subject: [PATCH] Add RBAC policy for ec2 API security groups calls
+
+The revoke_security_group_ingress, revoke_security_group_ingress, and
+delete_security_group calls in the ec2 API were not restricted by policy
+checks.  This prevented a deployer from restricting their usage via
+roles or other checks.  Checks have been added for these calls.
+
+Based on commit d4056f8723cc6cefb28ff6e5a7c0df5ea77f82ef but modified
+for the backport.
+
+Closes-Bug: #1290537
+Change-Id: I4bf681bedd68ed2216b429d34db735823e0a6189
+(cherry picked from commit dbb7dd03fea68120ef5ac9bbb1b3f184e3f2eacc)
+---
+ nova/api/ec2/cloud.py            | 10 +++++++++
+ nova/tests/api/ec2/test_cloud.py | 44 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 54 insertions(+)
+
+diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
+index 94ff160..36c2f12 100644
+--- a/nova/api/ec2/cloud.py
++++ b/nova/api/ec2/cloud.py
+@@ -30,6 +30,7 @@ from oslo.config import cfg
+ from nova.api.ec2 import ec2utils
+ from nova.api.ec2 import inst_state
+ from nova.api.metadata import password
++from nova.api.openstack import extensions
+ from nova.api import validator
+ from nova import availability_zones
+ from nova import block_device
+@@ -85,6 +86,9 @@ LOG = logging.getLogger(__name__)
+ 
+ QUOTAS = quota.QUOTAS
+ 
++security_group_authorizer = extensions.extension_authorizer('compute',
++                                                            'security_groups')
++
+ 
+ def validate_ec2_id(val):
+     if not validator.validate_str()(val):
+@@ -631,6 +635,8 @@ class CloudController(object):
+         security_group = self.security_group_api.get(context, group_name,
+                                                      group_id)
+ 
++        security_group_authorizer(context, security_group)
++
+         prevalues = kwargs.get('ip_permissions', [kwargs])
+ 
+         rule_ids = []
+@@ -665,6 +671,8 @@ class CloudController(object):
+         security_group = self.security_group_api.get(context, group_name,
+                                                      group_id)
+ 
++        security_group_authorizer(context, security_group)
++
+         prevalues = kwargs.get('ip_permissions', [kwargs])
+         postvalues = []
+         for values in prevalues:
+@@ -737,6 +745,8 @@ class CloudController(object):
+         security_group = self.security_group_api.get(context, group_name,
+                                                      group_id)
+ 
++        security_group_authorizer(context, security_group)
++
+         self.security_group_api.destroy(context, security_group)
+ 
+         return True
+diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py
+index 269a738..b28d194 100644
+--- a/nova/tests/api/ec2/test_cloud.py
++++ b/nova/tests/api/ec2/test_cloud.py
+@@ -23,6 +23,7 @@ import copy
+ import datetime
+ import functools
+ import iso8601
++import mock
+ import os
+ import string
+ import tempfile
+@@ -47,6 +48,7 @@ from nova.image import s3
+ from nova.network import api as network_api
+ from nova.network import neutronv2
+ from nova.openstack.common import log as logging
++from nova.openstack.common import policy as common_policy
+ from nova.openstack.common import timeutils
+ from nova import test
+ from nova.tests.api.openstack.compute.contrib import (
+@@ -471,6 +473,34 @@ class CloudTestCase(test.TestCase):
+         delete = self.cloud.delete_security_group
+         self.assertRaises(exception.MissingParameter, delete, self.context)
+ 
++    def test_delete_security_group_policy_not_allowed(self):
++        rules = common_policy.Rules(
++                {'compute_extension:security_groups':
++                    common_policy.parse_rule('project_id:%(project_id)s')})
++        common_policy.set_rules(rules)
++
++        with mock.patch.object(self.cloud.security_group_api,
++                'get') as get:
++            get.return_value = {'project_id': 'invalid'}
++
++            self.assertRaises(exception.PolicyNotAuthorized,
++                    self.cloud.delete_security_group, self.context,
++                    'fake-name', 'fake-id')
++
++    def test_authorize_security_group_ingress_policy_not_allowed(self):
++        rules = common_policy.Rules(
++                {'compute_extension:security_groups':
++                    common_policy.parse_rule('project_id:%(project_id)s')})
++        common_policy.set_rules(rules)
++
++        with mock.patch.object(self.cloud.security_group_api,
++                'get') as get:
++            get.return_value = {'project_id': 'invalid'}
++
++            self.assertRaises(exception.PolicyNotAuthorized,
++                    self.cloud.authorize_security_group_ingress, self.context,
++                    'fake-name', 'fake-id')
++
+     def test_authorize_security_group_ingress(self):
+         kwargs = {'project_id': self.context.project_id, 'name': 'test'}
+         sec = db.security_group_create(self.context, kwargs)
+@@ -575,6 +605,20 @@ class CloudTestCase(test.TestCase):
+         db.security_group_destroy(self.context, sec2['id'])
+         db.security_group_destroy(self.context, sec1['id'])
+ 
++    def test_revoke_security_group_ingress_policy_not_allowed(self):
++        rules = common_policy.Rules(
++                {'compute_extension:security_groups':
++                    common_policy.parse_rule('project_id:%(project_id)s')})
++        common_policy.set_rules(rules)
++
++        with mock.patch.object(self.cloud.security_group_api,
++                'get') as get:
++            get.return_value = {'project_id': 'invalid'}
++
++            self.assertRaises(exception.PolicyNotAuthorized,
++                    self.cloud.revoke_security_group_ingress, self.context,
++                    'fake-name', 'fake-id')
++
+     def test_revoke_security_group_ingress(self):
+         kwargs = {'project_id': self.context.project_id, 'name': 'test'}
+         sec = db.security_group_create(self.context, kwargs)
diff --git a/openstack-nova.spec b/openstack-nova.spec
index 49b78da..725f4ca 100644
--- a/openstack-nova.spec
+++ b/openstack-nova.spec
@@ -2,7 +2,7 @@
 
 Name:             openstack-nova
 Version:          2013.2.3
-Release:          1%{?dist}
+Release:          2%{?dist}
 Summary:          OpenStack Compute (nova)
 
 Group:            Applications/System
@@ -39,6 +39,9 @@ Source30:         openstack-nova-novncproxy.sysconfig
 #
 Patch0001: 0001-Ensure-we-don-t-access-the-net-when-building-docs.patch
 Patch0002: 0002-remove-runtime-dep-on-python-pbr.patch
+Patch0003: 0003-notify-calling-process-we-are-ready-to-serve.patch
+Patch0004: 0004-Move-notification-point-to-a-better-place.patch
+Patch0005: 0005-Add-RBAC-policy-for-ec2-API-security-groups-calls.patch
 
 BuildArch:        noarch
 BuildRequires:    intltool
@@ -396,6 +399,9 @@ This package contains documentation files for nova.
 
 %patch0001 -p1
 %patch0002 -p1
+%patch0003 -p1
+%patch0004 -p1
+%patch0005 -p1
 
 find . \( -name .gitignore -o -name .placeholder \) -delete
 
@@ -902,6 +908,11 @@ fi
 %endif
 
 %changelog
+* Mon Jun 30 2014 Vladan Popovic <vpopovic at redhat.com> 2013.2.3-2
+- Add RBAC policy for ec2 API security groups calls - CVE-2014-0167
+- Move notification point to a better place
+- notify calling process we are ready to serve
+
 * Fri Apr 04 2014 Xavier Queralt <xqueralt@@redhat.com> - 2013.2.3-1
 - Update to stable/havana 2013.2.3 release
 


More information about the scm-commits mailing list