cfn-model 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/bin/cfn_parse +8 -0
  3. data/lib/cfn-model/model/bucket_policy.rb +13 -0
  4. data/lib/cfn-model/model/cfn_model.rb +64 -0
  5. data/lib/cfn-model/model/ec2_instance.rb +15 -0
  6. data/lib/cfn-model/model/ec2_network_interface.rb +18 -0
  7. data/lib/cfn-model/model/iam_group.rb +15 -0
  8. data/lib/cfn-model/model/iam_managed_policy.rb +14 -0
  9. data/lib/cfn-model/model/iam_policy.rb +14 -0
  10. data/lib/cfn-model/model/iam_role.rb +14 -0
  11. data/lib/cfn-model/model/iam_user.rb +16 -0
  12. data/lib/cfn-model/model/iam_user_to_group_addition.rb +10 -0
  13. data/lib/cfn-model/model/load_balancer.rb +37 -0
  14. data/lib/cfn-model/model/model_element.rb +101 -0
  15. data/lib/cfn-model/model/policy.rb +10 -0
  16. data/lib/cfn-model/model/policy_document.rb +52 -0
  17. data/lib/cfn-model/model/principal.rb +34 -0
  18. data/lib/cfn-model/model/queue_policy.rb +13 -0
  19. data/lib/cfn-model/model/references.rb +52 -0
  20. data/lib/cfn-model/model/security_group.rb +18 -0
  21. data/lib/cfn-model/model/security_group_egress.rb +29 -0
  22. data/lib/cfn-model/model/security_group_ingress.rb +38 -0
  23. data/lib/cfn-model/model/statement.rb +38 -0
  24. data/lib/cfn-model/model/topic_policy.rb +13 -0
  25. data/lib/cfn-model/parser/cfn_parser.rb +126 -0
  26. data/lib/cfn-model/parser/ec2_instance_parser.rb +10 -0
  27. data/lib/cfn-model/parser/ec2_network_interface_parser.rb +10 -0
  28. data/lib/cfn-model/parser/iam_group_parser.rb +17 -0
  29. data/lib/cfn-model/parser/iam_role_parser.rb +20 -0
  30. data/lib/cfn-model/parser/iam_user_parser.rb +58 -0
  31. data/lib/cfn-model/parser/load_balancer_parser.rb +10 -0
  32. data/lib/cfn-model/parser/load_balancer_v2_parser.rb +15 -0
  33. data/lib/cfn-model/parser/parser_error.rb +13 -0
  34. data/lib/cfn-model/parser/parser_registry.rb +34 -0
  35. data/lib/cfn-model/parser/policy_document_parser.rb +44 -0
  36. data/lib/cfn-model/parser/security_group_parser.rb +83 -0
  37. data/lib/cfn-model/parser/with_policy_document_parser.rb +10 -0
  38. data/lib/cfn-model/schema/AWS_CloudFront_Distribution.yml +42 -0
  39. data/lib/cfn-model/schema/AWS_EC2_Instance.yml +146 -0
  40. data/lib/cfn-model/schema/AWS_EC2_NetworkInterface.yml +62 -0
  41. data/lib/cfn-model/schema/AWS_EC2_NetworkInterfaceAttachment.yml +24 -0
  42. data/lib/cfn-model/schema/AWS_EC2_SecurityGroup.yml +71 -0
  43. data/lib/cfn-model/schema/AWS_EC2_SecurityGroupEgress.yml +27 -0
  44. data/lib/cfn-model/schema/AWS_EC2_SecurityGroupIngress.yml +27 -0
  45. data/lib/cfn-model/schema/AWS_ElasticLoadBalancingV2_LoadBalancer.yml +56 -0
  46. data/lib/cfn-model/schema/AWS_ElasticLoadBalancing_LoadBalancer.yml +188 -0
  47. data/lib/cfn-model/schema/AWS_IAM_Group.yml +23 -0
  48. data/lib/cfn-model/schema/AWS_IAM_ManagedPolicy.yml +34 -0
  49. data/lib/cfn-model/schema/AWS_IAM_Policy.yml +36 -0
  50. data/lib/cfn-model/schema/AWS_IAM_Role.yml +28 -0
  51. data/lib/cfn-model/schema/AWS_IAM_User.yml +38 -0
  52. data/lib/cfn-model/schema/AWS_IAM_UserToGroupAddition.yml +23 -0
  53. data/lib/cfn-model/schema/AWS_Lambda_Permission.yml +24 -0
  54. data/lib/cfn-model/schema/AWS_S3_BucketPolicy.yml +21 -0
  55. data/lib/cfn-model/schema/AWS_SNS_TopicPolicy.yml +23 -0
  56. data/lib/cfn-model/schema/AWS_SQS_QueuePolicy.yml +23 -0
  57. data/lib/cfn-model/schema/schema.yml.erb +17 -0
  58. data/lib/cfn-model/validator/cloudformation_validator.rb +12 -0
  59. data/lib/cfn-model/validator/reference_validator.rb +83 -0
  60. data/lib/cfn-model/validator/resource_type_validator.rb +34 -0
  61. data/lib/cfn-model/validator/schema_generator.rb +86 -0
  62. data/lib/cfn-model.rb +2 -0
  63. metadata +120 -0
@@ -0,0 +1,126 @@
1
+ require 'yaml'
2
+ require 'cfn-model/validator/cloudformation_validator'
3
+ require 'cfn-model/validator/reference_validator'
4
+ require_relative 'parser_registry'
5
+ require_relative 'parser_error'
6
+ Dir["#{__dir__}/../model/*.rb"].each { |model| require "cfn-model/model/#{File.basename(model, '.rb')}" }
7
+
8
+ ##
9
+ # This class is the heart of the matter. It will take a CloudFormation template
10
+ # and return a CfnModel object to represent the underlying document in a way
11
+ # that is hopefully more convenient for (cfn-nag rule) developers to work with
12
+ #
13
+ class CfnParser
14
+ # this will convert any !Ref or !GetAtt into tranditional hash like in json
15
+ YAML.add_domain_type('', 'Ref') { |type, val| { 'Ref' => val } }
16
+
17
+ %w(GetAtt Join Base64 Sub Split Select ImportValue GetAZs FindInMap And Or If Not).each do |function_name|
18
+ YAML.add_domain_type('', function_name) { |type, val| { "Fn::#{function_name}" => val } }
19
+ end
20
+
21
+ ##
22
+ # Given raw json/yml CloudFormation template, returns a CfnModel object
23
+ # or raise ParserErrors if something is amiss with the format
24
+ def parse(cloudformation_yml)
25
+ cfn_hash = pre_validate_model cloudformation_yml
26
+
27
+ cfn_model = CfnModel.new
28
+ cfn_model.raw_model = cfn_hash
29
+
30
+ # pass 1: wire properties into ModelElement objects
31
+ transform_hash_into_model_elements cfn_hash, cfn_model
32
+
33
+ # pass 2: tie together separate resources only where necessary to make life easier for rule logic
34
+ post_process_resource_model_elements cfn_model
35
+
36
+ cfn_model
37
+ end
38
+
39
+ private
40
+
41
+ def post_process_resource_model_elements(cfn_model)
42
+ cfn_model.resources.each do |_, resource|
43
+ resource_parser_class = ParserRegistry.instance.registry[resource.class.to_s]
44
+
45
+ next if resource_parser_class.nil?
46
+
47
+ resource_parser = resource_parser_class.new
48
+ resource_parser.parse(cfn_model: cfn_model,
49
+ resource: resource)
50
+ end
51
+ end
52
+
53
+ # pass 0: validate basic syntax so we can make some assumptions down stream
54
+ # even within the parsing code
55
+ def transform_hash_into_model_elements(cfn_hash, cfn_model)
56
+ cfn_hash['Resources'].each do |resource_name, resource|
57
+ resource_class = class_from_type_name resource['Type']
58
+
59
+ resource_object = resource_class.new
60
+ resource_object.logical_resource_id = resource_name
61
+ resource_object.resource_type = resource['Type']
62
+
63
+ assign_fields_based_upon_properties resource_object, resource
64
+
65
+ cfn_model.resources[resource_name] = resource_object
66
+ end
67
+ cfn_model
68
+ end
69
+
70
+ def pre_validate_model(cloudformation_yml)
71
+ errors = CloudFormationValidator.new.validate cloudformation_yml
72
+ if !errors.nil? && !errors.empty?
73
+ raise ParserError.new('Basic CloudFormation syntax error', errors)
74
+ end
75
+
76
+ cfn_hash = YAML.load cloudformation_yml
77
+
78
+ unresolved_refs = ReferenceValidator.new.unresolved_references(cfn_hash)
79
+ unless unresolved_refs.empty?
80
+ raise ParserError.new("Unresolved logical resource ids: #{unresolved_refs.to_a}")
81
+ end
82
+ cfn_hash
83
+ end
84
+
85
+ def assign_fields_based_upon_properties(resource_object, resource)
86
+ unless resource['Properties'].nil?
87
+ resource['Properties'].each do |property_name, property_value|
88
+ resource_object.send("#{initial_lower(property_name)}=", property_value)
89
+ end
90
+ end
91
+ end
92
+
93
+ def class_from_type_name(type_name)
94
+ begin
95
+ resource_class = Object.const_get type_name, inherit=false
96
+ rescue NameError
97
+ # puts "Never seen class: #{type_name} so going dynamic"
98
+ resource_class = generate_resource_class_from_type type_name
99
+ end
100
+ resource_class
101
+ end
102
+
103
+ def initial_lower(str)
104
+ str.slice(0).downcase + str[1..(str.length)]
105
+ end
106
+
107
+ def generate_resource_class_from_type(type_name)
108
+ resource_class = Class.new(ModelElement)
109
+
110
+ module_names = type_name.split('::')
111
+ if module_names.first == 'Custom'
112
+ Object.const_set(module_names[1], resource_class)
113
+ elsif module_names.first == 'AWS'
114
+ begin
115
+ module_constant = AWS.const_get(module_names[1])
116
+ rescue NameError
117
+ module_constant = Module.new
118
+ module_constant.const_set(module_names[1], module_constant)
119
+ end
120
+ module_constant.const_set(module_names[2], resource_class)
121
+ else
122
+ raise "Unknown namespace in resource type: #{module_names.first}"
123
+ end
124
+ resource_class
125
+ end
126
+ end
@@ -0,0 +1,10 @@
1
+ class Ec2InstanceParser
2
+ def parse(cfn_model:, resource:)
3
+ ec2_instance = resource
4
+
5
+ ec2_instance.security_groups = ec2_instance.securityGroupIds.map do |security_group_reference|
6
+ cfn_model.find_security_group_by_group_id(security_group_reference)
7
+ end
8
+ ec2_instance
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class Ec2NetworkInterfaceParser
2
+ def parse(cfn_model:, resource:)
3
+ network_interface = resource
4
+
5
+ network_interface.security_groups = network_interface.groupSet.map do |security_group_reference|
6
+ cfn_model.find_security_group_by_group_id(security_group_reference)
7
+ end
8
+ network_interface
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'cfn-model/model/iam_role'
2
+ require 'cfn-model/model/policy'
3
+ require_relative 'policy_document_parser'
4
+
5
+ class IamGroupParser
6
+ def parse(cfn_model:, resource:)
7
+ iam_group = resource
8
+
9
+ iam_group.policy_objects = iam_group.policies.map do |policy|
10
+ new_policy = Policy.new
11
+ new_policy.policyName = policy['PolicyName']
12
+ new_policy.policyDocument = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
13
+ new_policy
14
+ end
15
+ iam_group
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'cfn-model/model/iam_role'
2
+ require 'cfn-model/model/policy'
3
+ require_relative 'policy_document_parser'
4
+
5
+ class IamRoleParser
6
+ def parse(cfn_model:, resource:)
7
+ iam_role = resource
8
+
9
+ iam_role.assume_role_policy_document = PolicyDocumentParser.new.parse(iam_role.assumeRolePolicyDocument)
10
+
11
+ iam_role.policy_objects = iam_role.policies.map do |policy|
12
+ new_policy = Policy.new
13
+ new_policy.policy_name = policy['PolicyName']
14
+ new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
15
+ new_policy
16
+ end
17
+
18
+ iam_role
19
+ end
20
+ end
@@ -0,0 +1,58 @@
1
+ require 'cfn-model/model/policy_document'
2
+ require 'cfn-model/model/policy'
3
+ require_relative 'policy_document_parser'
4
+
5
+ class IamUserParser
6
+ def parse(cfn_model:, resource:)
7
+ iam_user = resource
8
+
9
+ iam_user.policy_objects = iam_user.policies.map do |policy|
10
+ new_policy = Policy.new
11
+ new_policy.policy_name = policy['PolicyName']
12
+ new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
13
+ new_policy
14
+ end
15
+
16
+ iam_user.groups.each { |group_name| iam_user.group_names << group_name }
17
+
18
+ user_to_group_additions = cfn_model.resources_by_type 'AWS::IAM::UserToGroupAddition'
19
+ user_to_group_additions.each do |user_to_group_addition|
20
+
21
+ if user_to_group_addition_has_username(user_to_group_addition.users,iam_user)
22
+ iam_user.group_names << user_to_group_addition.groupName
23
+
24
+ # we need to figure out the story on resolving Refs i think for this to be real
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def user_to_group_addition_has_username(addition_user_names, user_to_find)
32
+ addition_user_names.each do |addition_user_name|
33
+ if addition_user_name == user_to_find.userName
34
+ return true
35
+ end
36
+
37
+ if addition_user_name.is_a? Hash
38
+ if !addition_user_name['Ref'].nil?
39
+ if addition_user_name['Ref'] == user_to_find.logical_resource_id
40
+ return true
41
+ end
42
+ end
43
+ end
44
+ end
45
+ false
46
+ end
47
+
48
+ # def resolve_user_logical_resource_id(user)
49
+ # if not user['Ref'].nil?
50
+ # user['Ref']
51
+ # elsif not user['Fn::GetAtt'].nil?
52
+ # fail 'Arn not legal for user to group addition'
53
+ # else
54
+ # @dangler
55
+ # end
56
+ # end
57
+
58
+ end
@@ -0,0 +1,10 @@
1
+ class LoadBalancerParser
2
+ def parse(cfn_model:, resource:)
3
+ load_balancer = resource
4
+
5
+ load_balancer.security_groups = load_balancer.securityGroups.map do |security_group_reference|
6
+ cfn_model.find_security_group_by_group_id(security_group_reference)
7
+ end
8
+ load_balancer
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ class LoadBalancerV2Parser
2
+ def parse(cfn_model:, resource:)
3
+ load_balancer = resource
4
+
5
+ #could be a List<Subnet::Id>
6
+ # if load_balancer.subnets.size < 2
7
+ # raise ParserError.new("Load Balancer must have at least two subnets: #{load_balancer.logical_resource_id}")
8
+ # end
9
+
10
+ load_balancer.security_groups = load_balancer.securityGroups.map do |security_group_reference|
11
+ cfn_model.find_security_group_by_group_id(security_group_reference)
12
+ end
13
+ load_balancer
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class ParserError < RuntimeError
2
+ attr_accessor :errors
3
+
4
+ def initialize(message, validation_errors=nil)
5
+ super(message)
6
+ @message = message
7
+ @errors = validation_errors
8
+ end
9
+
10
+ def to_s
11
+ "#{@message}#{@errors.nil? ? '' : ':'}#{@errors.to_s}"
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ Dir["#{__dir__}/*_parser.rb"].each { |model| require "cfn-model/parser/#{File.basename(model, '.rb')}" }
2
+
3
+ class ParserRegistry
4
+ attr_reader :registry
5
+
6
+ def initialize
7
+ @registry = {
8
+ 'AWS::EC2::SecurityGroup' => SecurityGroupParser,
9
+ 'AWS::EC2::NetworkInterface' => Ec2NetworkInterfaceParser,
10
+ 'AWS::EC2::Instance' => Ec2InstanceParser,
11
+ 'AWS::ElasticLoadBalancing::LoadBalancer' => LoadBalancerParser,
12
+ 'AWS::ElasticLoadBalancingV2::LoadBalancer' => LoadBalancerV2Parser,
13
+ 'AWS::IAM::Group' => IamGroupParser,
14
+ 'AWS::IAM::User' => IamUserParser,
15
+ 'AWS::IAM::Role' => IamRoleParser,
16
+ 'AWS::IAM::Policy' => WithPolicyDocumentParser,
17
+ 'AWS::IAM::ManagedPolicy' => WithPolicyDocumentParser,
18
+ 'AWS::S3::BucketPolicy' => WithPolicyDocumentParser,
19
+ 'AWS::SNS::TopicPolicy' => WithPolicyDocumentParser,
20
+ 'AWS::SQS::QueuePolicy' => WithPolicyDocumentParser
21
+ }
22
+ end
23
+
24
+ def self.instance
25
+ if @instance.nil?
26
+ @instance = ParserRegistry.new
27
+ end
28
+ @instance
29
+ end
30
+
31
+ # def add_parser(resource_name, parser)
32
+ # @registry[resource_name] = parser
33
+ # end
34
+ end
@@ -0,0 +1,44 @@
1
+ require 'cfn-model/model/iam_policy'
2
+ require 'cfn-model/model/policy_document'
3
+
4
+ class PolicyDocumentParser
5
+ def parse(raw_policy_document)
6
+ policy_document = PolicyDocument.new
7
+
8
+ policy_document.version = raw_policy_document['Version']
9
+
10
+ policy_document.statements = streamline_array(raw_policy_document['Statement']) do |statement|
11
+ parse_statement statement
12
+ end
13
+
14
+ policy_document
15
+ end
16
+
17
+ private
18
+
19
+ def parse_statement(raw_statement)
20
+ statement = Statement.new
21
+ statement.effect = raw_statement['Effect']
22
+ statement.sid = raw_statement['Sid']
23
+ statement.condition = raw_statement['Condition']
24
+ statement.actions = streamline_array(raw_statement['Action'])
25
+ statement.not_actions = streamline_array(raw_statement['NotAction'])
26
+ statement.resources = streamline_array(raw_statement['Resource'])
27
+ statement.not_resources = streamline_array(raw_statement['NotResource'])
28
+ statement.principal = raw_statement['Principal']
29
+ statement.not_principal = raw_statement['NotPrincipal']
30
+ statement
31
+ end
32
+
33
+ def streamline_array(one_or_more)
34
+ return [] if one_or_more.nil?
35
+
36
+ if one_or_more.is_a?(String) || one_or_more.is_a?(Hash)
37
+ [block_given? ? yield(one_or_more) : one_or_more]
38
+ elsif one_or_more.is_a? Array
39
+ one_or_more.map { |one| block_given? ? yield(one) : one }
40
+ else
41
+ raise "unexpected object in streamline_array: #{one_or_more} #{one_or_more.class}"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,83 @@
1
+ require_relative 'parser_error'
2
+ require 'cfn-model/model/security_group_egress'
3
+ require 'cfn-model/model/security_group_ingress'
4
+ require 'cfn-model/model/references'
5
+
6
+ class SecurityGroupParser
7
+
8
+ def parse(cfn_model:, resource:)
9
+ security_group = resource
10
+
11
+ objectify_egress security_group
12
+
13
+ objectify_ingress security_group
14
+
15
+ wire_ingress_rules_to_security_group(cfn_model: cfn_model, security_group: security_group)
16
+ wire_egress_rules_to_security_group(cfn_model: cfn_model, security_group: security_group)
17
+ security_group
18
+ end
19
+
20
+ private
21
+
22
+ def objectify_ingress(security_group)
23
+ if security_group.securityGroupIngress.is_a? Hash
24
+ security_group.securityGroupIngress = [security_group.securityGroupIngress]
25
+ end
26
+
27
+ security_group.ingresses = security_group.securityGroupIngress.map do |ingress|
28
+ ingress_object = AWS::EC2::SecurityGroupIngress.new
29
+ ingress.each do |k,v|
30
+ ingress_object.send("#{initialLower(k)}=", v)
31
+ end
32
+ #ingress_object.valid?
33
+ ingress_object
34
+ end
35
+ end
36
+
37
+ def objectify_egress(security_group)
38
+ if security_group.securityGroupEgress.is_a? Hash
39
+ security_group.securityGroupEgress = [security_group.securityGroupEgress]
40
+ end
41
+
42
+ security_group.egresses = security_group.securityGroupEgress.map do |egress|
43
+ egress_object = AWS::EC2::SecurityGroupEgress.new
44
+ egress.each do |k,v|
45
+ egress_object.send("#{initialLower(k)}=", v)
46
+ end
47
+ #egress_object.valid?
48
+ egress_object
49
+ end
50
+ end
51
+
52
+ def initialLower(str)
53
+ str.slice(0).downcase + str[1..(str.length)]
54
+ end
55
+
56
+ def wire_ingress_rules_to_security_group(cfn_model:, security_group:)
57
+ ingress_rules = cfn_model.resources_by_type 'AWS::EC2::SecurityGroupIngress'
58
+ ingress_rules.each do |security_group_ingress|
59
+ group_id = References.resolve_security_group_id(security_group_ingress.groupId)
60
+
61
+ # standalone ingress rules are legal - referencing an external security group
62
+ next if group_id.nil?
63
+
64
+ if security_group.logical_resource_id == group_id
65
+ security_group.ingresses << security_group_ingress
66
+ end
67
+ end
68
+ end
69
+
70
+ def wire_egress_rules_to_security_group(cfn_model:, security_group:)
71
+ egress_rules = cfn_model.resources_by_type 'AWS::EC2::SecurityGroupEgress'
72
+ egress_rules.each do |security_group_egress|
73
+ group_id = References.resolve_security_group_id(security_group_egress.groupId)
74
+
75
+ # standalone ingress rules are legal - referencing an external security group
76
+ next if group_id.nil?
77
+
78
+ if security_group.logical_resource_id == group_id
79
+ security_group.egresses << security_group_egress
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,10 @@
1
+ require 'cfn-model/model/iam_policy'
2
+ require 'cfn-model/model/policy_document'
3
+ require_relative 'policy_document_parser'
4
+
5
+ class WithPolicyDocumentParser
6
+ def parse(cfn_model:, resource:)
7
+ resource.policy_document = PolicyDocumentParser.new.parse(resource.policyDocument)
8
+ resource
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ ---
2
+ type: map
3
+ mapping:
4
+ Type:
5
+ type: str
6
+ required: yes
7
+ pattern: /AWS::CloudFront::Distribution/
8
+ Properties:
9
+ type: map
10
+ required: yes
11
+ mapping:
12
+ DistributionConfig:
13
+ type: map
14
+ required: yes
15
+ mapping:
16
+ Aliases:
17
+ type: seq
18
+ required: no
19
+ sequence:
20
+ - type: any
21
+ CacheBehaviors:
22
+ type: seq
23
+ required: no
24
+ sequence:
25
+ - type: any
26
+ DefaultCacheBehavior:
27
+ type: any
28
+ required: yes
29
+ Enabled:
30
+ type: any
31
+ required: yes
32
+ Origins:
33
+ type: seq
34
+ required: yes
35
+ sequence:
36
+ - type: any
37
+ =:
38
+ type: any
39
+ =:
40
+ type: any
41
+ =:
42
+ type: any
@@ -0,0 +1,146 @@
1
+ ---
2
+ type: map
3
+ mapping:
4
+ Type:
5
+ type: str
6
+ required: yes
7
+ pattern: /AWS::EC2::Instance/
8
+ Properties:
9
+ type: map
10
+ required: yes
11
+ mapping:
12
+ BlockDeviceMappings:
13
+ type: seq
14
+ required: no
15
+ sequence:
16
+ - type: map
17
+ mapping:
18
+ DeviceName:
19
+ type: any
20
+ required: yes
21
+ =:
22
+ type: any
23
+ ImageId:
24
+ type: any
25
+ required: yes
26
+ Ipv6Addresses:
27
+ type: seq
28
+ required: no
29
+ sequence:
30
+ - type: map
31
+ mapping:
32
+ Ipv6Address:
33
+ type: any
34
+ required: yes
35
+ =:
36
+ type: any
37
+ NetworkInterfaces:
38
+ type: seq
39
+ required: no
40
+ sequence:
41
+ - type: map
42
+ mapping:
43
+ DeviceIndex:
44
+ type: any
45
+ required: yes
46
+ GroupSet:
47
+ type: seq
48
+ required: no
49
+ sequence:
50
+ - type: any
51
+ Ipv6Addresses:
52
+ type: seq
53
+ required: no
54
+ sequence:
55
+ - type: map
56
+ mapping:
57
+ Ipv6Address:
58
+ type: any
59
+ required: yes
60
+ =:
61
+ type: any
62
+ PrivateIpAddresses:
63
+ type: seq
64
+ required: no
65
+ sequence:
66
+ - type: map
67
+ mapping:
68
+ PrivateIpAddress:
69
+ type: any
70
+ required: yes
71
+ Primary:
72
+ type: any
73
+ required: yes
74
+ =:
75
+ type: any
76
+ =:
77
+ type: any
78
+
79
+ # sigh this could be List<AWS::EC2::SecurityGroup::Id> so can't enfore seq
80
+ SecurityGroupIds:
81
+ type: any
82
+ required: no
83
+
84
+ # sigh this could be List<AWS::EC2::SecurityGroup::GroupName> so can't enfore seq
85
+ SecurityGroups:
86
+ type: any
87
+ required: no
88
+
89
+ SsmAssociations:
90
+ type: seq
91
+ required: no
92
+ sequence:
93
+ - type: map
94
+ mapping:
95
+ AssociationParameters:
96
+ type: seq
97
+ required: no
98
+ sequence:
99
+ - type: map
100
+ mapping:
101
+ Key:
102
+ type: any
103
+ required: yes
104
+ Value:
105
+ type: seq
106
+ required: yes
107
+ sequence:
108
+ - type: any
109
+ =:
110
+ type: any
111
+ DocumentName:
112
+ required: yes
113
+ type: any
114
+
115
+ Tags:
116
+ type: seq
117
+ required: no
118
+ sequence:
119
+ - type: map
120
+ mapping:
121
+ Key:
122
+ type: any
123
+ required: yes
124
+ Value:
125
+ type: any
126
+ required: yes
127
+ =:
128
+ type: any
129
+ Volumes:
130
+ type: seq
131
+ required: no
132
+ sequence:
133
+ - type: map
134
+ mapping:
135
+ Device:
136
+ type: any
137
+ required: yes
138
+ VolumeId:
139
+ type: any
140
+ required: yes
141
+ =:
142
+ type: any
143
+ =:
144
+ type: any
145
+ =:
146
+ type: any