Limit maximum size of all templates

Templates of an extremely large size can eat up tons of CPU time,
memory and storage. By refusing to parse any template over a certain
size, we can prevent users from abusing the service.

Fixes bug #1214234

Change-Id: I2f731c8e2fc9e1f497199e310de81fa48c9582af
This commit is contained in:
Clint Byrum 2013-08-21 13:24:17 -07:00
parent 1623b03517
commit 9fe8cbacd2
5 changed files with 31 additions and 1 deletions

View File

@ -70,6 +70,9 @@
# Keystone role for heat template-defined users (string value)
#heat_stack_user_role=heat_stack_user
# Maximum raw byte size of any template. (integer value)
#max_template_size=524288
#
# Options defined in heat.common.crypt

View File

@ -81,7 +81,10 @@ service_opts = [
help='Instance connection to cfn/cw API validate certs if ssl'),
cfg.StrOpt('heat_stack_user_role',
default="heat_stack_user",
help='Keystone role for heat template-defined users')]
help='Keystone role for heat template-defined users'),
cfg.IntOpt('max_template_size',
default=524288,
help='Maximum raw byte size of any template.')]
db_opts = [
cfg.StrOpt('sql_connection',

View File

@ -297,3 +297,7 @@ class HTTPExceptionDisguise(Exception):
def __init__(self, exception):
self.exc = exception
self.tb = sys.exc_info()[2]
class TemplateTooBig(OpenstackException):
message = _('Template exceeds maximum allowed size.')

View File

@ -17,6 +17,12 @@ import re
import yaml
import json
from oslo.config import cfg
from heat.common import exception
cfg.CONF.import_opt('max_template_size', 'heat.common.config')
HEAT_VERSIONS = (u'2012-12-12',)
CFN_VERSIONS = (u'2010-09-09',)
@ -43,6 +49,8 @@ def parse(tmpl_str, add_template_sections=True):
This includes determination of whether the string is using the
JSON or YAML format.
'''
if len(tmpl_str) > cfg.CONF.max_template_size:
raise exception.TemplateTooBig()
if tmpl_str.startswith('{'):
tpl = json.loads(tmpl_str)
else:

View File

@ -14,8 +14,11 @@
from testtools import skipIf
import os
import yaml
from heat.engine import clients
from heat.common import config
from heat.common import exception
from heat.common import template_format
from heat.tests.common import HeatTestCase
from heat.tests import utils
@ -89,6 +92,15 @@ Outputs: {}
tpl2 = template_format.parse(yaml2)
self.assertEqual(tpl1, tpl2)
def test_long_yaml(self):
template = {'HeatTemplateVersion': '2012-12-12'}
template['Resources'] = ['a'] * (config.cfg.CONF.max_template_size / 3)
limit = config.cfg.CONF.max_template_size
long_yaml = yaml.safe_dump(template)
self.assertTrue(len(long_yaml) > limit)
self.assertRaises(exception.TemplateTooBig, template_format.parse,
long_yaml)
class YamlEnvironmentTest(HeatTestCase):