Skip to content

Commit d7d062a

Browse files
committed
Option to restrict amp glance image owner
This patch adds an optional configuration setting that allows an operator to restrict the amphora glance image selection to a specific owner id. This is a recommended security setting for clouds that allow user uploadable images. Change-Id: I73347b5b3e868d13974cd6ca6bada9cdf75773fe Closes-Bug: #1620629
1 parent 2eaabf0 commit d7d062a

File tree

11 files changed

+71
-27
lines changed

11 files changed

+71
-27
lines changed

devstack/plugin.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ function build_octavia_worker_image {
2525
$OCTAVIA_DIR/diskimage-create/diskimage-create.sh -s 2 -o $OCTAVIA_AMP_IMAGE_FILE
2626
fi
2727
upload_image file://${OCTAVIA_AMP_IMAGE_FILE} $TOKEN
28+
29+
image_id=$(glance image-list --property-filter name=${OCTAVIA_AMP_IMAGE_NAME} | awk '/ amphora-x64-haproxy / {print $2}')
30+
owner_id=$(glance image-show ${image_id} | awk '/ owner / {print $4}')
31+
iniset $OCTAVIA_CONF controller_worker amp_image_owner_id ${owner_id}
32+
2833
}
2934

3035
function create_octavia_accounts {

etc/octavia.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@
135135
# parameters is needed. Using tags is the recommended way to refer to images.
136136
# amp_image_id =
137137
# amp_image_tag =
138+
# Optional owner ID used to restrict glance images to one owner ID.
139+
# This is a recommended security setting.
140+
# amp_image_owner_id =
138141
# Nova parameters to use when booting amphora
139142
# amp_flavor_id =
140143
# amp_ssh_key_name =

octavia/common/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@
216216
deprecated_for_removal=True,
217217
deprecated_reason='Superseded by amp_image_tag option.',
218218
help=_('Glance image id for the Amphora image to boot')),
219+
cfg.StrOpt('amp_image_owner_id',
220+
default='',
221+
help=_('Restrict glance image selection to a specific '
222+
'owner ID. This is a recommended security setting.')),
219223
cfg.StrOpt('amp_ssh_key_name',
220224
default='',
221225
help=_('SSH key name used to boot the Amphora')),

octavia/common/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,4 @@
331331
AMP_ACTION_START = 'start'
332332
AMP_ACTION_STOP = 'stop'
333333
AMP_ACTION_RELOAD = 'reload'
334+
GLANCE_IMAGE_ACTIVE = 'active'

octavia/compute/compute_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ComputeBase(object):
2222

2323
@abc.abstractmethod
2424
def build(self, name="amphora_name", amphora_flavor=None,
25-
image_id=None, image_tag=None,
25+
image_id=None, image_tag=None, image_owner=None,
2626
key_name=None, sec_groups=None, network_ids=None,
2727
config_drive_files=None, user_data=None, server_group_id=None):
2828
"""Build a new amphora.

octavia/compute/drivers/noop_driver/driver.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ def __init__(self):
2828
self.computeconfig = {}
2929

3030
def build(self, name="amphora_name", amphora_flavor=None,
31-
image_id=None, image_tag=None,
31+
image_id=None, image_tag=None, image_owner=None,
3232
key_name=None, sec_groups=None, network_ids=None,
3333
config_drive_files=None, user_data=None, port_ids=None,
3434
server_group_id=None):
3535
LOG.debug("Compute %s no-op, build name %s, amphora_flavor %s, "
36-
"image_id %s, image_tag %s, key_name %s, sec_groups %s, "
37-
"network_ids %s, config_drive_files %s, user_data %s, "
38-
"port_ids %s, server_group_id %s",
36+
"image_id %s, image_tag %s, image_owner %s, key_name %s, "
37+
"sec_groups %s, network_ids %s, config_drive_files %s, "
38+
"user_data %s, port_ids %s, server_group_id %s",
3939
self.__class__.__name__,
40-
name, amphora_flavor, image_id, image_tag,
40+
name, amphora_flavor, image_id, image_tag, image_owner,
4141
key_name, sec_groups, network_ids, config_drive_files,
4242
user_data, port_ids, server_group_id)
4343
self.computeconfig[(name, amphora_flavor, image_id, image_tag,
44-
key_name, user_data)] = (
44+
image_owner, key_name, user_data)] = (
4545
name, amphora_flavor,
46-
image_id, image_tag, key_name, sec_groups,
46+
image_id, image_tag, image_owner, key_name, sec_groups,
4747
network_ids, config_drive_files,
4848
user_data, port_ids, 'build')
4949
compute_id = uuidutils.generate_uuid()
@@ -87,13 +87,13 @@ def __init__(self):
8787
self.driver = NoopManager()
8888

8989
def build(self, name="amphora_name", amphora_flavor=None,
90-
image_id=None, image_tag=None,
90+
image_id=None, image_tag=None, image_owner=None,
9191
key_name=None, sec_groups=None, network_ids=None,
9292
config_drive_files=None, user_data=None, port_ids=None,
9393
server_group_id=None):
9494

9595
compute_id = self.driver.build(name, amphora_flavor,
96-
image_id, image_tag,
96+
image_id, image_tag, image_owner,
9797
key_name, sec_groups, network_ids,
9898
config_drive_files, user_data, port_ids,
9999
server_group_id)

octavia/compute/drivers/nova_driver.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,21 @@
3232
CONF.import_group('nova', 'octavia.common.config')
3333

3434

35-
def _extract_amp_image_id_by_tag(client, image_tag):
36-
images = list(client.images.list(
37-
filters={'tag': [image_tag]},
38-
sort='created_at:desc',
39-
limit=2))
35+
def _extract_amp_image_id_by_tag(client, image_tag, image_owner):
36+
if image_owner:
37+
images = list(client.images.list(
38+
filters={'tag': [image_tag],
39+
'owner': image_owner,
40+
'status': constants.GLANCE_IMAGE_ACTIVE},
41+
sort='created_at:desc',
42+
limit=2))
43+
else:
44+
images = list(client.images.list(
45+
filters={'tag': [image_tag],
46+
'status': constants.GLANCE_IMAGE_ACTIVE},
47+
sort='created_at:desc',
48+
limit=2))
49+
4050
if not images:
4151
raise exceptions.GlanceNoTaggedImages(tag=image_tag)
4252
image_id = images[0]['id']
@@ -50,15 +60,15 @@ def _extract_amp_image_id_by_tag(client, image_tag):
5060
return image_id
5161

5262

53-
def _get_image_uuid(client, image_id, image_tag):
63+
def _get_image_uuid(client, image_id, image_tag, image_owner):
5464
if image_id:
5565
if image_tag:
5666
LOG.warning(
5767
_LW("Both amp_image_id and amp_image_tag options defined. "
58-
"Using the former."))
68+
"Using the amp_image_id."))
5969
return image_id
6070

61-
return _extract_amp_image_id_by_tag(client, image_tag)
71+
return _extract_amp_image_id_by_tag(client, image_tag, image_owner)
6272

6373

6474
class VirtualMachineManager(compute_base.ComputeBase):
@@ -84,7 +94,7 @@ def __init__(self):
8494
self.server_groups = self._nova_client.server_groups
8595

8696
def build(self, name="amphora_name", amphora_flavor=None,
87-
image_id=None, image_tag=None,
97+
image_id=None, image_tag=None, image_owner=None,
8898
key_name=None, sec_groups=None, network_ids=None,
8999
port_ids=None, config_drive_files=None, user_data=None,
90100
server_group_id=None):
@@ -126,7 +136,7 @@ def build(self, name="amphora_name", amphora_flavor=None,
126136
"group": server_group_id}
127137

128138
image_id = _get_image_uuid(
129-
self._glance_client, image_id, image_tag)
139+
self._glance_client, image_id, image_tag, image_owner)
130140
amphora = self.manager.create(
131141
name=name, image=image_id, flavor=amphora_flavor,
132142
key_name=key_name, security_groups=sec_groups,

octavia/controller/worker/tasks/compute_tasks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def execute(self, amphora_id, ports=None, config_drive_files=None,
8383
amphora_flavor=CONF.controller_worker.amp_flavor_id,
8484
image_id=CONF.controller_worker.amp_image_id,
8585
image_tag=CONF.controller_worker.amp_image_tag,
86+
image_owner=CONF.controller_worker.amp_image_owner_id,
8687
key_name=key_name,
8788
sec_groups=CONF.controller_worker.amp_secgroup_list,
8889
network_ids=network_ids,

octavia/tests/unit/compute/drivers/test_nova_driver.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,19 @@ def test__get_image_uuid_tag(self):
3535
with mock.patch.object(nova_common,
3636
'_extract_amp_image_id_by_tag',
3737
return_value='fakeid') as extract:
38-
image_id = nova_common._get_image_uuid(client, '', 'faketag')
38+
image_id = nova_common._get_image_uuid(client, '', 'faketag', None)
3939
self.assertEqual('fakeid', image_id)
40-
extract.assert_called_with(client, 'faketag')
40+
extract.assert_called_with(client, 'faketag', None)
4141

4242
def test__get_image_uuid_notag(self):
4343
client = mock.Mock()
44-
image_id = nova_common._get_image_uuid(client, 'fakeid', '')
44+
image_id = nova_common._get_image_uuid(client, 'fakeid', '', None)
4545
self.assertEqual('fakeid', image_id)
4646

4747
def test__get_image_uuid_id_beats_tag(self):
4848
client = mock.Mock()
49-
image_id = nova_common._get_image_uuid(client, 'fakeid', 'faketag')
49+
image_id = nova_common._get_image_uuid(client, 'fakeid',
50+
'faketag', None)
5051
self.assertEqual('fakeid', image_id)
5152

5253

@@ -62,15 +63,16 @@ def test_no_images(self):
6263
self.client.images.list.return_value = []
6364
self.assertRaises(
6465
exceptions.GlanceNoTaggedImages,
65-
nova_common._extract_amp_image_id_by_tag, self.client, 'faketag')
66+
nova_common._extract_amp_image_id_by_tag, self.client,
67+
'faketag', None)
6668

6769
def test_single_image(self):
6870
images = [
6971
{'id': uuidutils.generate_uuid(), 'tag': 'faketag'}
7072
]
7173
self.client.images.list.return_value = images
7274
image_id = nova_common._extract_amp_image_id_by_tag(self.client,
73-
'faketag')
75+
'faketag', None)
7476
self.assertIn(image_id, images[0]['id'])
7577

7678
def test_multiple_images_returns_one_of_images(self):
@@ -80,7 +82,7 @@ def test_multiple_images_returns_one_of_images(self):
8082
]
8183
self.client.images.list.return_value = images
8284
image_id = nova_common._extract_amp_image_id_by_tag(self.client,
83-
'faketag')
85+
'faketag', None)
8486
self.assertIn(image_id, [image['id'] for image in images])
8587

8688

octavia/tests/unit/controller/worker/tasks/test_compute_tasks.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ def setUp(self):
8787
@mock.patch('stevedore.driver.DriverManager.driver')
8888
def test_compute_create(self, mock_driver, mock_conf, mock_jinja):
8989

90+
image_owner_id = uuidutils.generate_uuid()
91+
conf = oslo_fixture.Config(cfg.CONF)
92+
conf.config(group="controller_worker",
93+
amp_image_owner_id=image_owner_id)
94+
9095
createcompute = compute_tasks.ComputeCreate()
9196

9297
mock_driver.build.return_value = COMPUTE_ID
@@ -100,6 +105,7 @@ def test_compute_create(self, mock_driver, mock_conf, mock_jinja):
100105
amphora_flavor=AMP_FLAVOR_ID,
101106
image_id=AMP_IMAGE_ID,
102107
image_tag=AMP_IMAGE_TAG,
108+
image_owner=image_owner_id,
103109
key_name=AMP_SSH_KEY_NAME,
104110
sec_groups=AMP_SEC_GROUPS,
105111
network_ids=AMP_NET,
@@ -134,6 +140,9 @@ def test_compute_create(self, mock_driver, mock_conf, mock_jinja):
134140

135141
createcompute.revert(COMPUTE_ID, _amphora_mock.id)
136142

143+
conf.config(group="controller_worker",
144+
amp_image_owner_id='')
145+
137146
@mock.patch('jinja2.Environment.get_template')
138147
@mock.patch('octavia.amphorae.backends.agent.'
139148
'agent_jinja_cfg.AgentJinjaTemplater.'
@@ -160,6 +169,7 @@ def test_compute_create_user_data(self, mock_driver,
160169
amphora_flavor=AMP_FLAVOR_ID,
161170
image_id=AMP_IMAGE_ID,
162171
image_tag=AMP_IMAGE_TAG,
172+
image_owner='',
163173
key_name=AMP_SSH_KEY_NAME,
164174
sec_groups=AMP_SEC_GROUPS,
165175
network_ids=AMP_NET,
@@ -219,6 +229,7 @@ def test_compute_create_without_ssh_access(self, mock_driver,
219229
amphora_flavor=AMP_FLAVOR_ID,
220230
image_id=AMP_IMAGE_ID,
221231
image_tag=AMP_IMAGE_TAG,
232+
image_owner='',
222233
key_name=None,
223234
sec_groups=AMP_SEC_GROUPS,
224235
network_ids=AMP_NET,
@@ -276,6 +287,7 @@ def test_compute_create_cert(self, mock_driver, mock_conf, mock_jinja):
276287
amphora_flavor=AMP_FLAVOR_ID,
277288
image_id=AMP_IMAGE_ID,
278289
image_tag=AMP_IMAGE_TAG,
290+
image_owner='',
279291
key_name=AMP_SSH_KEY_NAME,
280292
sec_groups=AMP_SEC_GROUPS,
281293
network_ids=AMP_NET,

0 commit comments

Comments
 (0)