Add workaround for AWS S3 API, verify md5 hash, exit non-zero on validate failure

This commit is contained in:
Stefan Reimer 2021-03-11 19:25:02 +01:00
parent f6e3df67bb
commit 7a66cf3ec5
5 changed files with 35 additions and 3 deletions

View File

@ -1,5 +1,10 @@
# Changelog
## 0.9.9
- Add workaround for inconsistent AWS API S3 GetBucketLocation
- validate now exits with non-zero exit code if valiation of any template failed
- the embedded md5 hash in templates are now verified reading the template
## 0.9.8
- Remove support for FortyTwo legacy mode as AWS now behaves as it should
- Add support for embedded custom output yaml format and removed hardcoded kubezero output template

View File

@ -2,7 +2,7 @@ import logging
__author__ = "Stefan Reimer"
__email__ = "stefan@zero-downtimet.net"
__version__ = "0.9.8"
__version__ = "0.9.9"
# Set up logging to ``/dev/null`` like a library is supposed to.

View File

@ -78,7 +78,9 @@ def validate(cb, stack_names, multi):
stacks = _find_stacks(cb, stack_names, multi)
for s in stacks:
s.validate()
ret = s.validate()
if ret:
sys.exit(ret)
@click.command()

View File

@ -12,3 +12,7 @@ class InvalidProjectDir(Exception):
class InvalidHook(Exception):
"""My documentation"""
class ChecksumError(Exception):
"""My documentation"""

View File

@ -15,7 +15,7 @@ from .utils import dict_merge, search_refs, ensure_dir, get_s3_url
from .connection import BotoConnection
from .jinja import JinjaEnv, read_config_file
from . import __version__
from .exceptions import ParameterNotFound, ParameterIllegalValue
from .exceptions import ParameterNotFound, ParameterIllegalValue, ChecksumError
from .hooks import exec_hooks
import cfnlint.core
@ -207,6 +207,20 @@ class Stack(object):
except KeyError:
pass
# Get checksum
if not self.md5:
try:
self.md5 = self.cfn_data['Metadata']['Template']['Hash']
# Verify embedded md5 hash
source_cfn = re.sub('Hash: [0-9a-f]{32}', 'Hash: __HASH__', self.cfn_template)
our_md5 = hashlib.md5(source_cfn.encode('utf-8')).hexdigest()
if (our_md5 != self.md5):
raise ChecksumError("Template hash checksum mismatch! Expected: {} Got: {}".format(self.md5, our_md5)) from None
except KeyError:
raise ChecksumError("Template missing Hash checksum!") from None
# Add CloudBender dependencies
include = []
search_refs(self.cfn_data, include, self.mode)
@ -315,6 +329,7 @@ class Stack(object):
self.cfn_data = yaml.load(self.cfn_template, Loader=SafeLoaderIgnoreUnknown)
self._parse_metadata()
else:
logger.debug('Using cached cfn template %s.', self.stackname)
@ -356,8 +371,10 @@ class Stack(object):
if len(matches):
for match in matches:
logger.error(formatter._format(match))
return 1
else:
logger.info("Passed.")
return 0
def get_outputs(self, include='.*', values=False):
""" gets outputs of the stack """
@ -766,6 +783,10 @@ class Stack(object):
# so we need the region, AWS as usual
(bucket, path) = get_s3_url(self.template_bucket_url, self.rel_path, self.stackname + ".yaml")
bucket_region = self.connection_manager.call('s3', 'get_bucket_location', {'Bucket': bucket}, profile=self.profile, region=self.region)['LocationConstraint']
# If bucket is in us-east-1 AWS returns 'none' cause reasons grrr
if not bucket_region:
bucket_region = 'us-east-1'
kwargs['TemplateURL'] = 'https://{}.s3.{}.amazonaws.com/{}'.format(bucket, bucket_region, path)
else:
kwargs['TemplateBody'] = self.cfn_template