Browse Source

Don't store signal_url for ec2 signaling of deployments

As part of a CVE keystone has started checking[1] the timestamp
of signed ec2 token with default TTL of 15 mins. We can't
store the ec2 url anymore for future use for those.

This moves the caching logic to BaseWaitConditionHandle class.

Conflicts:
	heat/engine/resources/signal_responder.py
	heat/tests/test_signal.py

[1] https://review.opendev.org/#/c/724124/

Change-Id: I6b74faed820caccd39210bd48a212b2dedca46b9
Task: 39985
Related-Bug: #1872737
(cherry picked from commit 3047ca7d36)
changes/59/733959/6
Rabi Mishra 1 month ago
parent
commit
95296e55c6
6 changed files with 27 additions and 12 deletions
  1. +2
    -6
      heat/engine/resources/signal_responder.py
  2. +9
    -0
      heat/engine/resources/wait_condition.py
  3. +3
    -2
      heat/tests/aws/test_waitcondition.py
  4. +4
    -1
      heat/tests/engine/service/test_stack_resources.py
  5. +4
    -1
      heat/tests/test_metadata_refresh.py
  6. +5
    -2
      heat/tests/test_signal.py

+ 2
- 6
heat/engine/resources/signal_responder.py View File

@@ -15,6 +15,7 @@ from keystoneclient.contrib.ec2 import utils as ec2_utils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from six.moves.urllib import parse as urlparse

from heat.common import exception
@@ -124,10 +125,6 @@ class SignalResponder(stack_user.StackUser):

:param signal_type: either WAITCONDITION or SIGNAL.
"""
stored = self.data().get('ec2_signed_url')
if stored is not None:
return stored

access_key = self.data().get('access_key')
secret_key = self.data().get('secret_key')

@@ -170,7 +167,7 @@ class SignalResponder(stack_user.StackUser):
'SignatureVersion': '2',
'AWSAccessKeyId': access_key,
'Timestamp':
self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ")
timeutils.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
}}
# Sign the request
signer = ec2_utils.Ec2Signer(secret_key)
@@ -180,7 +177,6 @@ class SignalResponder(stack_user.StackUser):
url = "%s%s?%s" % (signal_url.lower(),
path, qs)

self.data_set('ec2_signed_url', url)
return url

def _delete_ec2_signed_url(self):


+ 9
- 0
heat/engine/resources/wait_condition.py View File

@@ -41,6 +41,15 @@ class BaseWaitConditionHandle(signal_responder.SignalResponder):
'SUCCESS',
)

def _get_ec2_signed_url(self, signal_type=signal_responder.WAITCONDITION):
stored = self.data().get('ec2_signed_url')
if stored is not None:
return stored
url = super(BaseWaitConditionHandle,
self)._get_ec2_signed_url(signal_type)
self.data_set('ec2_signed_url', url)
return url

def handle_create(self):
super(BaseWaitConditionHandle, self).handle_create()
self.resource_id_set(self._get_user_id())


+ 3
- 2
heat/tests/aws/test_waitcondition.py View File

@@ -375,7 +375,9 @@ class WaitConditionHandleTest(common.HeatTestCase):
def test_handle(self):
stack_id = 'STACKABCD1234'
stack_name = 'test_stack2'
created_time = datetime.datetime(2012, 11, 29, 13, 49, 37)
now = datetime.datetime(2012, 11, 29, 13, 49, 37)
timeutils.set_time_override(now)
self.addCleanup(timeutils.clear_time_override)
self.stack = self.create_stack(stack_id=stack_id,
stack_name=stack_name)

@@ -387,7 +389,6 @@ class WaitConditionHandleTest(common.HeatTestCase):
# clear the url
rsrc.data_set('ec2_signed_url', None, False)

rsrc.created_time = created_time
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
connection_url = "".join([
'http://server.test:8000/v1/waitcondition/',


+ 4
- 1
heat/tests/engine/service/test_stack_resources.py View File

@@ -17,6 +17,7 @@ import six

from heat.common import exception
from heat.common import identifier
from heat.engine.clients.os import heat_plugin
from heat.engine.clients.os import keystone
from heat.engine.clients.os.keystone import fake_keystoneclient as fake_ks
from heat.engine import dependencies
@@ -451,11 +452,13 @@ class StackResourcesServiceTest(common.HeatTestCase):
self.assertEqual(exception.InvalidBreakPointHook,
ex.exc_info[0])

@mock.patch.object(heat_plugin.HeatClientPlugin, 'get_heat_cfn_url')
@mock.patch.object(res.Resource, 'metadata_update')
@mock.patch.object(res.Resource, 'signal')
@mock.patch.object(service.EngineService, '_get_stack')
def test_signal_calls_metadata_update(self, mock_get, mock_signal,
mock_update):
mock_update, mock_get_cfn):
mock_get_cfn.return_value = 'http://server.test:8000/v1'
# fake keystone client
self.patchobject(keystone.KeystoneClientPlugin, '_create',
return_value=fake_ks.FakeKeystoneClient())


+ 4
- 1
heat/tests/test_metadata_refresh.py View File

@@ -16,6 +16,7 @@ from oslo_serialization import jsonutils
from heat.common import identifier
from heat.common import template_format
from heat.engine.clients.os import glance
from heat.engine.clients.os import heat_plugin
from heat.engine.clients.os import nova
from heat.engine import environment
from heat.engine.resources.aws.cfn.wait_condition_handle import (
@@ -222,14 +223,16 @@ class WaitConditionMetadataUpdateTest(common.HeatTestCase):

@mock.patch.object(nova.NovaClientPlugin, 'find_flavor_by_name_or_id')
@mock.patch.object(glance.GlanceClientPlugin, 'find_image_by_name_or_id')
@mock.patch.object(heat_plugin.HeatClientPlugin, 'get_heat_cfn_url')
@mock.patch.object(instance.Instance, 'handle_create')
@mock.patch.object(instance.Instance, 'check_create_complete')
@mock.patch.object(scheduler.TaskRunner, '_sleep')
@mock.patch.object(WaitConditionHandle, 'identifier')
def test_wait_metadata(self, mock_identifier, mock_sleep,
mock_check, mock_handle, *args):
mock_check, mock_handle, mock_get, *args):
"""Tests a wait condition metadata update after a signal call."""

mock_get.return_value = 'http://server.test:8000/v1'
# Setup Stack
temp = template_format.parse(TEST_TEMPLATE_WAIT_CONDITION)
template = tmpl.Template(temp)


+ 5
- 2
heat/tests/test_signal.py View File

@@ -15,6 +15,7 @@ import datetime

from keystoneauth1 import exceptions as kc_exceptions
import mock
from oslo_utils import timeutils
import six
from six.moves.urllib import parse as urlparse

@@ -151,6 +152,10 @@ class SignalTest(common.HeatTestCase):

@mock.patch.object(heat_plugin.HeatClientPlugin, 'get_heat_cfn_url')
def test_FnGetAtt_alarm_url(self, mock_get):
now = datetime.datetime(2012, 11, 29, 13, 49, 37)
timeutils.set_time_override(now)
self.addCleanup(timeutils.clear_time_override)

# Setup
stack_id = stack_name = 'FnGetAtt-alarm-url'
stack = self._create_stack(TEMPLATE_CFN_SIGNAL,
@@ -160,8 +165,6 @@ class SignalTest(common.HeatTestCase):
mock_get.return_value = 'http://server.test:8000/v1'

rsrc = stack['signal_handler']
created_time = datetime.datetime(2012, 11, 29, 13, 49, 37)
rsrc.created_time = created_time

self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)



Loading…
Cancel
Save