Skip to content

Commit

Permalink
Add rule I3042 to check for hardcoded partitions, account IDs, and re…
Browse files Browse the repository at this point in the history
…gions in an ARN (#1805)

* New rule to check resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number
* Updating HardCodedArnProperties rule to allow for parameterized Region and AccountId and updated related test templates

Co-authored-by: Arun Donti <dontirun@gmail.com>
  • Loading branch information
kddejong and dontirun authored Mar 8, 2021
1 parent a06423e commit 4acb81b
Show file tree
Hide file tree
Showing 9 changed files with 780 additions and 1 deletion.
104 changes: 104 additions & 0 deletions src/cfnlint/rules/resources/HardCodedArnProperties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""
import re
import six
from cfnlint.rules import CloudFormationLintRule
from cfnlint.rules import RuleMatch


class HardCodedArnProperties(CloudFormationLintRule):
"""Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number"""
id = 'I3042'
shortdesc = 'ARNs should use correctly placed Pseudo Parameters'
description = 'Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number'
source_url = ''
tags = ['resources']
regex = re.compile(r'arn:(\$\{[^:]*::[^:]*}|[^:]*):[^:]+:(\$\{[^:]*::[^:]*}|[^:]*):(\$\{[^:]*::[^:]*}|[^:]*)')

def __init__(self):
"""Init"""
super(HardCodedArnProperties, self).__init__()
self.config_definition = {
'partition': {
'default': True,
'type': 'boolean',
},
'region': {
'default': False,
'type': 'boolean',
},
'accountId': {
'default': False,
'type': 'boolean',
},
}
self.configure()

def _match_values(self, cfnelem, path):
"""Recursively search for values matching the searchRegex"""
values = []
if isinstance(cfnelem, dict):
for key in cfnelem:
pathprop = path[:]
pathprop.append(key)
values.extend(self._match_values(cfnelem[key], pathprop))
elif isinstance(cfnelem, list):
for index, item in enumerate(cfnelem):
pathprop = path[:]
pathprop.append(index)
values.extend(self._match_values(item, pathprop))
else:
# Leaf node
if isinstance(cfnelem, six.string_types): # and re.match(searchRegex, cfnelem):
for variable in re.findall(self.regex, cfnelem):
values.append(path + [variable])

return values

def match_values(self, cfn):
"""
Search for values in all parts of the templates that match the searchRegex
"""
results = []
results.extend(self._match_values(cfn.template.get('Resources', {}), []))
# Globals are removed during a transform. They need to be checked manually
results.extend(self._match_values(cfn.template.get('Globals', {}), []))
return results

def match(self, cfn):
"""Check CloudFormation Resources"""
matches = []

# Get a list of paths to every leaf node string containing at least one ${parameter}
parameter_string_paths = self.match_values(cfn)
# We want to search all of the paths to check if each one contains an 'Fn::Sub'
for parameter_string_path in parameter_string_paths:
path = ['Resources'] + parameter_string_path[:-1]
candidate = parameter_string_path[-1]

# !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# is valid even with aws as the account #. This handles empty string
if self.config['partition'] and not re.match(r'^\$\{\w+}|\$\{AWS::Partition}|$', candidate[0]):
# or not re.match(r'^(\$\{\w+}|\$\{AWS::Region}|)$', candidate[1]) or not re.match(r'^\$\{\w+}|\$\{AWS::AccountId}|aws|$', candidate[2]):
message = 'ARN in Resource {0} contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters'
matches.append(RuleMatch(
path,
message.format(path[1])
))
if self.config['region'] and not re.match(r'^(\$\{\w+}|\$\{AWS::Region}|)$', candidate[1]):
# or or not re.match(r'^\$\{\w+}|\$\{AWS::AccountId}|aws|$', candidate[2]):
message = 'ARN in Resource {0} contains hardcoded Region in ARN or incorrectly placed Pseudo Parameters'
matches.append(RuleMatch(
path,
message.format(path[1])
))
if self.config['accountId'] and not re.match(r'^\$\{\w+}|\$\{AWS::AccountId}|aws|$', candidate[2]):
message = 'ARN in Resource {0} contains hardcoded AccountId in ARN or incorrectly placed Pseudo Parameters'
matches.append(RuleMatch(
path,
message.format(path[1])
))

return matches
25 changes: 25 additions & 0 deletions test/fixtures/results/public/lambda-poller.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,30 @@
"ShortDescription": "Check if EOL Lambda Function Runtimes are used",
"Source": "https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html"
}
},
{
"Filename":"test/fixtures/templates/public/lambda-poller.yaml",
"Level":"Informational",
"Location":{
"End":{
"ColumnNumber":76,
"LineNumber":39
},
"Path":[
"Resources",
"PollerFunctionIamRole"
],
"Start":{
"ColumnNumber":12,
"LineNumber":39
}
},
"Message":"ARN in Resource LambdaExecutionRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule":{
"Description":"Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id":"I3042",
"ShortDescription":"ARNs should use correctly placed Pseudo Parameters",
"Source":""
}
}
]
196 changes: 196 additions & 0 deletions test/fixtures/results/quickstart/cis_benchmark.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,144 @@
[
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 60,
"LineNumber": 89
},
"Path": [
"Resources",
"MasterConfigRole",
"Properties",
"ManagedPolicyArns",
0
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 89
}
},
"Message": "ARN in Resource MasterConfigRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 64,
"LineNumber": 90
},
"Path": [
"Resources",
"MasterConfigRole",
"Properties",
"ManagedPolicyArns",
1
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 90
}
},
"Message": "ARN in Resource MasterConfigRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 54,
"LineNumber": 91
},
"Path": [
"Resources",
"MasterConfigRole",
"Properties",
"ManagedPolicyArns",
2
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 91
}
},
"Message": "ARN in Resource MasterConfigRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 77,
"LineNumber": 92
},
"Path": [
"Resources",
"MasterConfigRole",
"Properties",
"ManagedPolicyArns",
3
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 92
}
},
"Message": "ARN in Resource MasterConfigRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 77,
"LineNumber": 93
},
"Path": [
"Resources",
"MasterConfigRole",
"Properties",
"ManagedPolicyArns",
4
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 93
}
},
"Message": "ARN in Resource MasterConfigRole contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Warning",
Expand Down Expand Up @@ -1369,6 +1509,34 @@
"Source": "https://aws.amazon.com/blogs/devops/optimize-aws-cloudformation-templates/"
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 77,
"LineNumber": 1842
},
"Path": [
"Resources",
"RoleForCloudWatchEvents",
"Properties",
"ManagedPolicyArns",
0
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 1842
}
},
"Message": "ARN in Resource RoleForCloudWatchEvents contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Warning",
Expand Down Expand Up @@ -1479,6 +1647,34 @@
"Source": "https://github.com/aws-cloudformation/cfn-python-lint/blob/master/docs/cfn-resource-specification.md#valueprimitivetype"
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Informational",
"Location": {
"End": {
"ColumnNumber": 77,
"LineNumber": 2232
},
"Path": [
"Resources",
"RoleForDisableUnusedCredentialsFunction",
"Properties",
"ManagedPolicyArns",
0
],
"Start": {
"ColumnNumber": 13,
"LineNumber": 2232
}
},
"Message": "ARN in Resource RoleForDisableUnusedCredentialsFunction contains hardcoded Partition in ARN or incorrectly placed Pseudo Parameters",
"Rule": {
"Description": "Checks Resources if ARNs use correctly placed Pseudo Parameters instead of hardcoded Partition, Region, and Account Number",
"Id": "I3042",
"ShortDescription": "ARNs should use correctly placed Pseudo Parameters",
"Source": ""
}
},
{
"Filename": "test/fixtures/templates/quickstart/cis_benchmark.yaml",
"Level": "Warning",
Expand Down
Loading

0 comments on commit 4acb81b

Please sign in to comment.