in cfn_policy_validator/parsers/utils/arn_generator.py [0:0]
def try_generate_arn(self, resource_name, resource, attribute_or_ref, visited_values=None):
if visited_values is None:
visited_values = []
cfn_type = resource['Type']
split_cfn_type = cfn_type.split("::")
if len(split_cfn_type) != 3:
if len(split_cfn_type) == 4 and split_cfn_type[3].lower() == 'module':
raise ApplicationError(f'Unable to resolve {cfn_type}. CloudFormation modules are not yet supported.')
raise ApplicationError(f'Invalid resource type: {cfn_type}')
service_name = split_cfn_type[1]
resource_type = split_cfn_type[2]
arn_pattern = self.cfn_to_arn_map\
.get(service_name, {})\
.get(resource_type, {})\
.get(attribute_or_ref)
if arn_pattern is None:
return None
arn_pattern = arn_pattern['Value']
# arn_patterns follow the format: arn:${Partition}:sqs:${Region}:${Account}:${QueueName}
# where Partition, Account, and Region are standardized variable names
arn_pattern = arn_pattern.replace("${Partition}", self.account_config.partition)
arn_pattern = arn_pattern.replace("${Region}", self.account_config.region)
arn_pattern = arn_pattern.replace("${Account}", self.account_config.account_id)
# certain CFN types require some additional generation that is specific to the resource type
# for example, we include the exact path with any roles or users, ALBs and NLBs share the same cfn resource,
# but have different ARNs
custom_generator = self.custom_generators.get(cfn_type)
if custom_generator is not None:
arn_pattern = custom_generator(arn_pattern, resource_name, resource, visited_values)
# match any variable (anything not Partition, Account, Region) within brackets and replace with the resource name
# e.g. arn:aws:..:${SomeResourceName} -> arn:aws:..:ResourceName
regex = r"(?P<Variable>\${[^}]*})"
def callback(match):
return resource_name
arn_pattern = re.sub(regex, callback, arn_pattern)
return arn_pattern