cfn-model 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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