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.

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

Change-Id: I6b74faed820caccd39210bd48a212b2dedca46b9
Related-Bug: #1872737
This commit is contained in:
Rabi Mishra 2020-06-03 18:18:23 +05:30
parent abc8733dc1
commit 3047ca7d36
6 changed files with 27 additions and 12 deletions

View File

@ -16,6 +16,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 heat.common import exception
from heat.common.i18n import _
@ -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):

View File

@ -40,6 +40,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())

View File

@ -374,7 +374,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)
@ -386,7 +388,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/',

View File

@ -17,6 +17,7 @@ from oslo_messaging.rpc import dispatcher
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())

View File

@ -17,6 +17,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 (
@ -223,14 +224,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)

View File

@ -16,6 +16,7 @@ from unittest import mock
from urllib import parse as urlparse
from keystoneauth1 import exceptions as kc_exceptions
from oslo_utils import timeutils
from heat.common import exception
from heat.common import template_format
@ -150,6 +151,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,
@ -159,8 +164,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)