1 This upstream patch addresses CVE-2014-0167 and is tracked under |
|
2 Launchpad bug 1290537. It is addressed in Icehouse 2014.1 and Havana |
|
3 2013.2.4. |
|
4 |
|
5 commit dbb7dd03fea68120ef5ac9bbb1b3f184e3f2eacc |
|
6 Author: Andrew Laski <[email protected]> |
|
7 Date: Wed Apr 9 09:27:44 2014 -0400 |
|
8 |
|
9 Add RBAC policy for ec2 API security groups calls |
|
10 |
|
11 The revoke_security_group_ingress, revoke_security_group_ingress, and |
|
12 delete_security_group calls in the ec2 API were not restricted by policy |
|
13 checks. This prevented a deployer from restricting their usage via |
|
14 roles or other checks. Checks have been added for these calls. |
|
15 |
|
16 Based on commit d4056f8723cc6cefb28ff6e5a7c0df5ea77f82ef but modified |
|
17 for the backport. |
|
18 |
|
19 Closes-Bug: #1290537 |
|
20 Change-Id: I4bf681bedd68ed2216b429d34db735823e0a6189 |
|
21 |
|
22 diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py |
|
23 index 94ff160..36c2f12 100644 |
|
24 --- a/nova/api/ec2/cloud.py |
|
25 +++ b/nova/api/ec2/cloud.py |
|
26 @@ -30,6 +30,7 @@ from oslo.config import cfg |
|
27 from nova.api.ec2 import ec2utils |
|
28 from nova.api.ec2 import inst_state |
|
29 from nova.api.metadata import password |
|
30 +from nova.api.openstack import extensions |
|
31 from nova.api import validator |
|
32 from nova import availability_zones |
|
33 from nova import block_device |
|
34 @@ -85,6 +86,9 @@ LOG = logging.getLogger(__name__) |
|
35 |
|
36 QUOTAS = quota.QUOTAS |
|
37 |
|
38 +security_group_authorizer = extensions.extension_authorizer('compute', |
|
39 + 'security_groups') |
|
40 + |
|
41 |
|
42 def validate_ec2_id(val): |
|
43 if not validator.validate_str()(val): |
|
44 @@ -631,6 +635,8 @@ class CloudController(object): |
|
45 security_group = self.security_group_api.get(context, group_name, |
|
46 group_id) |
|
47 |
|
48 + security_group_authorizer(context, security_group) |
|
49 + |
|
50 prevalues = kwargs.get('ip_permissions', [kwargs]) |
|
51 |
|
52 rule_ids = [] |
|
53 @@ -665,6 +671,8 @@ class CloudController(object): |
|
54 security_group = self.security_group_api.get(context, group_name, |
|
55 group_id) |
|
56 |
|
57 + security_group_authorizer(context, security_group) |
|
58 + |
|
59 prevalues = kwargs.get('ip_permissions', [kwargs]) |
|
60 postvalues = [] |
|
61 for values in prevalues: |
|
62 @@ -737,6 +745,8 @@ class CloudController(object): |
|
63 security_group = self.security_group_api.get(context, group_name, |
|
64 group_id) |
|
65 |
|
66 + security_group_authorizer(context, security_group) |
|
67 + |
|
68 self.security_group_api.destroy(context, security_group) |
|
69 |
|
70 return True |
|
71 diff --git a/nova/tests/api/ec2/test_cloud.py b/nova/tests/api/ec2/test_cloud.py |
|
72 index 269a738..b28d194 100644 |
|
73 --- a/nova/tests/api/ec2/test_cloud.py |
|
74 +++ b/nova/tests/api/ec2/test_cloud.py |
|
75 @@ -23,6 +23,7 @@ import copy |
|
76 import datetime |
|
77 import functools |
|
78 import iso8601 |
|
79 +import mock |
|
80 import os |
|
81 import string |
|
82 import tempfile |
|
83 @@ -47,6 +48,7 @@ from nova.image import s3 |
|
84 from nova.network import api as network_api |
|
85 from nova.network import neutronv2 |
|
86 from nova.openstack.common import log as logging |
|
87 +from nova.openstack.common import policy as common_policy |
|
88 from nova.openstack.common import timeutils |
|
89 from nova import test |
|
90 from nova.tests.api.openstack.compute.contrib import ( |
|
91 @@ -471,6 +473,34 @@ class CloudTestCase(test.TestCase): |
|
92 delete = self.cloud.delete_security_group |
|
93 self.assertRaises(exception.MissingParameter, delete, self.context) |
|
94 |
|
95 + def test_delete_security_group_policy_not_allowed(self): |
|
96 + rules = common_policy.Rules( |
|
97 + {'compute_extension:security_groups': |
|
98 + common_policy.parse_rule('project_id:%(project_id)s')}) |
|
99 + common_policy.set_rules(rules) |
|
100 + |
|
101 + with mock.patch.object(self.cloud.security_group_api, |
|
102 + 'get') as get: |
|
103 + get.return_value = {'project_id': 'invalid'} |
|
104 + |
|
105 + self.assertRaises(exception.PolicyNotAuthorized, |
|
106 + self.cloud.delete_security_group, self.context, |
|
107 + 'fake-name', 'fake-id') |
|
108 + |
|
109 + def test_authorize_security_group_ingress_policy_not_allowed(self): |
|
110 + rules = common_policy.Rules( |
|
111 + {'compute_extension:security_groups': |
|
112 + common_policy.parse_rule('project_id:%(project_id)s')}) |
|
113 + common_policy.set_rules(rules) |
|
114 + |
|
115 + with mock.patch.object(self.cloud.security_group_api, |
|
116 + 'get') as get: |
|
117 + get.return_value = {'project_id': 'invalid'} |
|
118 + |
|
119 + self.assertRaises(exception.PolicyNotAuthorized, |
|
120 + self.cloud.authorize_security_group_ingress, self.context, |
|
121 + 'fake-name', 'fake-id') |
|
122 + |
|
123 def test_authorize_security_group_ingress(self): |
|
124 kwargs = {'project_id': self.context.project_id, 'name': 'test'} |
|
125 sec = db.security_group_create(self.context, kwargs) |
|
126 @@ -575,6 +605,20 @@ class CloudTestCase(test.TestCase): |
|
127 db.security_group_destroy(self.context, sec2['id']) |
|
128 db.security_group_destroy(self.context, sec1['id']) |
|
129 |
|
130 + def test_revoke_security_group_ingress_policy_not_allowed(self): |
|
131 + rules = common_policy.Rules( |
|
132 + {'compute_extension:security_groups': |
|
133 + common_policy.parse_rule('project_id:%(project_id)s')}) |
|
134 + common_policy.set_rules(rules) |
|
135 + |
|
136 + with mock.patch.object(self.cloud.security_group_api, |
|
137 + 'get') as get: |
|
138 + get.return_value = {'project_id': 'invalid'} |
|
139 + |
|
140 + self.assertRaises(exception.PolicyNotAuthorized, |
|
141 + self.cloud.revoke_security_group_ingress, self.context, |
|
142 + 'fake-name', 'fake-id') |
|
143 + |
|
144 def test_revoke_security_group_ingress(self): |
|
145 kwargs = {'project_id': self.context.project_id, 'name': 'test'} |
|
146 sec = db.security_group_create(self.context, kwargs) |
|