Skip to content

Commit

Permalink
#80 reorganize parsing so that parameter values are applied BEFORE mo…
Browse files Browse the repository at this point in the history
…del synthesis occurs. then resolve values when assigning to explicit model elements - so Ref, FindInMap and all that will be resolved
  • Loading branch information
erickascic committed May 4, 2020
1 parent 8d60dc0 commit d49cfca
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 31 deletions.
6 changes: 4 additions & 2 deletions lib/cfn-model/parser/cfn_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def parse(cloudformation_yml, parameter_values_json=nil, with_line_numbers=false

apply_parameter_values(cfn_model, parameter_values_json)

# pass 2: tie together separate resources only where necessary to make life easier for rule logic
post_process_resource_model_elements cfn_model

cfn_model
end

Expand Down Expand Up @@ -87,8 +90,7 @@ def parse_without_parameters(cloudformation_yml, with_line_numbers=false, condit
transform_hash_into_parameters cfn_hash, cfn_model
transform_hash_into_globals cfn_hash, cfn_model

# pass 2: tie together separate resources only where necessary to make life easier for rule logic
post_process_resource_model_elements cfn_model


cfn_model
end
Expand Down
5 changes: 3 additions & 2 deletions lib/cfn-model/parser/iam_group_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'cfn-model/model/iam_role'
require 'cfn-model/model/policy'
require 'cfn-model/model/references'
require_relative 'policy_document_parser'

class IamGroupParser
Expand All @@ -12,8 +13,8 @@ def parse(cfn_model:, resource:)
next unless policy.has_key? 'PolicyName'

new_policy = Policy.new
new_policy.policy_name = policy['PolicyName']
new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
new_policy
end.reject { |policy| policy.nil? }
iam_group
Expand Down
7 changes: 4 additions & 3 deletions lib/cfn-model/parser/iam_role_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

require 'cfn-model/model/iam_role'
require 'cfn-model/model/policy'
require 'cfn-model/model/references'
require_relative 'policy_document_parser'

class IamRoleParser
def parse(cfn_model:, resource:)
iam_role = resource

iam_role.assume_role_policy_document = PolicyDocumentParser.new.parse(iam_role.assumeRolePolicyDocument)
iam_role.assume_role_policy_document = PolicyDocumentParser.new.parse(cfn_model, iam_role.assumeRolePolicyDocument)

iam_role.policy_objects = iam_role.policies.map do |policy|
next unless policy.has_key? 'PolicyName'

new_policy = Policy.new
new_policy.policy_name = policy['PolicyName']
new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
new_policy
end.reject { |policy| policy.nil? }

Expand Down
9 changes: 5 additions & 4 deletions lib/cfn-model/parser/iam_user_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'cfn-model/model/policy_document'
require 'cfn-model/model/policy'
require 'cfn-model/model/references'
require_relative 'policy_document_parser'

class IamUserParser
Expand All @@ -12,8 +13,8 @@ def parse(cfn_model:, resource:)
next unless policy.has_key? 'PolicyName'

new_policy = Policy.new
new_policy.policy_name = policy['PolicyName']
new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
new_policy
end.reject { |policy| policy.nil? }

Expand All @@ -22,8 +23,8 @@ def parse(cfn_model:, resource:)
user_to_group_additions = cfn_model.resources_by_type 'AWS::IAM::UserToGroupAddition'
user_to_group_additions.each do |user_to_group_addition|

if user_to_group_addition_has_username(user_to_group_addition.users,iam_user)
iam_user.group_names << user_to_group_addition.groupName
if user_to_group_addition_has_username(user_to_group_addition.users, iam_user)
iam_user.group_names << References.resolve_value(cfn_model, user_to_group_addition.groupName)

# we need to figure out the story on resolving Refs i think for this to be real
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cfn-model/parser/kms_key_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def parse(cfn_model:, resource:)
kms_key = resource

new_policy = Policy.new
new_policy.policy_document = PolicyDocumentParser.new.parse(kms_key.keyPolicy)
new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, kms_key.keyPolicy)
kms_key.key_policy = new_policy

kms_key
Expand Down
28 changes: 15 additions & 13 deletions lib/cfn-model/parser/policy_document_parser.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
# frozen_string_literal: true

require 'cfn-model/model/iam_policy'
require 'cfn-model/model/references'

require 'cfn-model/model/policy_document'

class PolicyDocumentParser
def parse(raw_policy_document)
def parse(cfn_model, raw_policy_document)
policy_document = PolicyDocument.new

policy_document.version = raw_policy_document['Version']
policy_document.version = References.resolve_value(cfn_model, raw_policy_document['Version'])

policy_document.statements = streamline_array(raw_policy_document['Statement']) do |statement|
parse_statement statement
parse_statement cfn_model, statement
end

policy_document
end

private

def parse_statement(raw_statement)
def parse_statement(cfn_model, raw_statement)
statement = Statement.new
statement.effect = raw_statement['Effect']
statement.sid = raw_statement['Sid']
statement.condition = raw_statement['Condition']
statement.actions = streamline_array(raw_statement['Action'])
statement.not_actions = streamline_array(raw_statement['NotAction'])
statement.resources = streamline_array(raw_statement['Resource'])
statement.not_resources = streamline_array(raw_statement['NotResource'])
statement.principal = raw_statement['Principal']
statement.not_principal = raw_statement['NotPrincipal']
statement.effect = References.resolve_value(cfn_model, raw_statement['Effect'])
statement.sid = References.resolve_value(cfn_model, raw_statement['Sid'])
statement.condition = References.resolve_value(cfn_model, raw_statement['Condition'])
statement.actions = References.resolve_value(cfn_model, streamline_array(raw_statement['Action']))
statement.not_actions = References.resolve_value(cfn_model, streamline_array(raw_statement['NotAction']))
statement.resources = References.resolve_value(cfn_model, streamline_array(raw_statement['Resource']))
statement.not_resources = References.resolve_value(cfn_model, streamline_array(raw_statement['NotResource']))
statement.principal = References.resolve_value(cfn_model, raw_statement['Principal'])
statement.not_principal = References.resolve_value(cfn_model, raw_statement['NotPrincipal'])
statement
end

Expand Down
4 changes: 2 additions & 2 deletions lib/cfn-model/parser/security_group_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def objectify_ingress(cfn_model, security_group)
ingress_object = AWS::EC2::SecurityGroupIngress.new cfn_model
ingress.each do |k, v|
silently_fail do
ingress_object.send("#{initialLower(k)}=", v)
ingress_object.send("#{initialLower(k)}=", References.resolve_value(cfn_model, v))
mapped_at_least_one_attribute = true
end
end
Expand All @@ -59,7 +59,7 @@ def objectify_egress(cfn_model, security_group)
egress.each do |k, v|
next if k.match /::/
silently_fail do
egress_object.send("#{initialLower(k)}=", v)
egress_object.send("#{initialLower(k)}=", References.resolve_value(cfn_model, v))
mapped_at_least_one_attribute = true
end

Expand Down
2 changes: 1 addition & 1 deletion lib/cfn-model/parser/with_policy_document_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class WithPolicyDocumentParser
def parse(cfn_model:, resource:)
resource.policy_document = PolicyDocumentParser.new.parse(resource.policyDocument)
resource.policy_document = PolicyDocumentParser.new.parse(cfn_model, resource.policyDocument)
resource
end
end
1 change: 0 additions & 1 deletion spec/model/references_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,6 @@
END
cfn_model = CfnParser.new.parse cloudformation_yml

puts cfn_model.resources['SecGroup'].egresses[1]
actual_value = cfn_model.resources['SecGroup'].securityGroupEgress[1]['CidrIp']
expected_value = '1.2.3.4/32'
expect(actual_value).to eq expected_value
Expand Down
14 changes: 14 additions & 0 deletions spec/parser/cfn_parser_iam_role_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,18 @@
end
end
end

context 'an iam role with embedded refs in a policy', :moo8 do
it 'returns role with statements array of size 1' do
yaml_test_templates('iam_role/embedded_ref').each do |test_template|
cfn_model = @cfn_parser.parse IO.read(test_template), '{"Parameters":{"Resource":"*"}}'

roles = cfn_model.resources_by_type('AWS::IAM::Role')

expect(roles.size).to eq 1
role = roles.first
expect(role.policy_objects.first.policy_document.statements.first.resources.first).to eq '*'
end
end
end
end
4 changes: 2 additions & 2 deletions spec/parser/policy_document_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
'Action' => '*'
}

policy_document = @policy_document_parser.parse raw_policy_document
policy_document = @policy_document_parser.parse CfnModel.new, raw_policy_document

expect(policy_document.version).to eq '1234'
expect(policy_document.statements.size).to eq 1
Expand Down Expand Up @@ -50,7 +50,7 @@
}
]

policy_document = @policy_document_parser.parse raw_policy_document
policy_document = @policy_document_parser.parse CfnModel.new, raw_policy_document

expect(policy_document.version).to eq '1234'
expect(policy_document.statements.size).to eq 2
Expand Down
36 changes: 36 additions & 0 deletions spec/test_templates/yaml/iam_role/embedded_ref.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Parameters:
Resource:
Type: String

Resources:
HelperRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: awstestingLambdaExecutePolicies
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- tag:TagResources
- tag:UntagResources
- elasticloadbalancing:DescribeLoadBalancerAttributes
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
- elasticloadbalancing:ModifyLoadBalancerAttributes
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- s3:GetBucketPolicy
- s3:PutBucketPolicy
Resource: !Ref Resource

0 comments on commit d49cfca

Please sign in to comment.