cumulus-aws 0.11.1
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.
- checksums.yaml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE +202 -0
- data/README.md +41 -0
- data/autocomplete +137 -0
- data/bin/cumulus +658 -0
- data/cumulus +2 -0
- data/cumulus-aws.gemspec +20 -0
- data/lib/autoscaling/AutoScaling.rb +40 -0
- data/lib/autoscaling/loader/Loader.rb +56 -0
- data/lib/autoscaling/manager/Manager.rb +360 -0
- data/lib/autoscaling/models/AlarmConfig.rb +165 -0
- data/lib/autoscaling/models/AlarmDiff.rb +172 -0
- data/lib/autoscaling/models/AutoScalingDiff.rb +178 -0
- data/lib/autoscaling/models/GroupConfig.rb +330 -0
- data/lib/autoscaling/models/PolicyConfig.rb +135 -0
- data/lib/autoscaling/models/PolicyDiff.rb +73 -0
- data/lib/autoscaling/models/ScheduledActionDiff.rb +53 -0
- data/lib/autoscaling/models/ScheduledConfig.rb +96 -0
- data/lib/aws_extensions/ec2/DhcpOptions.rb +41 -0
- data/lib/aws_extensions/ec2/Instance.rb +29 -0
- data/lib/aws_extensions/ec2/NetworkAcl.rb +25 -0
- data/lib/aws_extensions/ec2/NetworkInterface.rb +14 -0
- data/lib/aws_extensions/ec2/RouteTable.rb +26 -0
- data/lib/aws_extensions/ec2/SecurityGroup.rb +16 -0
- data/lib/aws_extensions/ec2/Subnet.rb +28 -0
- data/lib/aws_extensions/ec2/Volume.rb +24 -0
- data/lib/aws_extensions/ec2/Vpc.rb +14 -0
- data/lib/aws_extensions/ec2/VpcEndpoint.rb +11 -0
- data/lib/aws_extensions/elb/BackendServerDescription.rb +12 -0
- data/lib/aws_extensions/elb/PolicyDescription.rb +14 -0
- data/lib/aws_extensions/kinesis/StreamDescription.rb +12 -0
- data/lib/aws_extensions/route53/AliasTarget.rb +21 -0
- data/lib/aws_extensions/s3/Bucket.rb +33 -0
- data/lib/aws_extensions/s3/BucketAcl.rb +28 -0
- data/lib/aws_extensions/s3/BucketCors.rb +17 -0
- data/lib/aws_extensions/s3/BucketLifecycle.rb +21 -0
- data/lib/aws_extensions/s3/BucketLogging.rb +18 -0
- data/lib/aws_extensions/s3/BucketNotification.rb +23 -0
- data/lib/aws_extensions/s3/BucketPolicy.rb +18 -0
- data/lib/aws_extensions/s3/BucketTagging.rb +15 -0
- data/lib/aws_extensions/s3/BucketVersioning.rb +14 -0
- data/lib/aws_extensions/s3/BucketWebsite.rb +49 -0
- data/lib/aws_extensions/s3/CORSRule.rb +27 -0
- data/lib/aws_extensions/s3/ReplicationConfiguration.rb +22 -0
- data/lib/cloudfront/CloudFront.rb +83 -0
- data/lib/cloudfront/loader/Loader.rb +31 -0
- data/lib/cloudfront/manager/Manager.rb +183 -0
- data/lib/cloudfront/models/CacheBehaviorConfig.rb +237 -0
- data/lib/cloudfront/models/CacheBehaviorDiff.rb +211 -0
- data/lib/cloudfront/models/CustomOriginConfig.rb +51 -0
- data/lib/cloudfront/models/CustomOriginDiff.rb +74 -0
- data/lib/cloudfront/models/DistributionConfig.rb +183 -0
- data/lib/cloudfront/models/DistributionDiff.rb +131 -0
- data/lib/cloudfront/models/InvalidationConfig.rb +37 -0
- data/lib/cloudfront/models/OriginConfig.rb +144 -0
- data/lib/cloudfront/models/OriginDiff.rb +86 -0
- data/lib/cloudfront/models/OriginSslProtocols.rb +28 -0
- data/lib/cloudfront/models/OriginSslProtocolsDiff.rb +39 -0
- data/lib/common/BaseLoader.rb +80 -0
- data/lib/common/manager/Manager.rb +148 -0
- data/lib/common/models/Diff.rb +114 -0
- data/lib/common/models/ListChange.rb +21 -0
- data/lib/common/models/TagsDiff.rb +55 -0
- data/lib/common/models/UTCTimeSource.rb +17 -0
- data/lib/conf/Configuration.rb +365 -0
- data/lib/ec2/EC2.rb +503 -0
- data/lib/ec2/IPProtocolMapping.rb +165 -0
- data/lib/ec2/loaders/EbsLoader.rb +19 -0
- data/lib/ec2/loaders/InstanceLoader.rb +32 -0
- data/lib/ec2/managers/EbsManager.rb +176 -0
- data/lib/ec2/managers/InstanceManager.rb +509 -0
- data/lib/ec2/models/EbsGroupConfig.rb +133 -0
- data/lib/ec2/models/EbsGroupDiff.rb +48 -0
- data/lib/ec2/models/InstanceConfig.rb +202 -0
- data/lib/ec2/models/InstanceDiff.rb +95 -0
- data/lib/elb/ELB.rb +148 -0
- data/lib/elb/loader/Loader.rb +65 -0
- data/lib/elb/manager/Manager.rb +581 -0
- data/lib/elb/models/AccessLogConfig.rb +82 -0
- data/lib/elb/models/AccessLogDiff.rb +47 -0
- data/lib/elb/models/HealthCheckConfig.rb +91 -0
- data/lib/elb/models/HealthCheckDiff.rb +50 -0
- data/lib/elb/models/ListenerConfig.rb +99 -0
- data/lib/elb/models/ListenerDiff.rb +91 -0
- data/lib/elb/models/LoadBalancerConfig.rb +239 -0
- data/lib/elb/models/LoadBalancerDiff.rb +265 -0
- data/lib/iam/IAM.rb +36 -0
- data/lib/iam/loader/Loader.rb +117 -0
- data/lib/iam/manager/IamGroups.rb +98 -0
- data/lib/iam/manager/IamResource.rb +288 -0
- data/lib/iam/manager/IamRoles.rb +112 -0
- data/lib/iam/manager/IamUsers.rb +54 -0
- data/lib/iam/manager/Manager.rb +29 -0
- data/lib/iam/migration/AssumeRoleUnifier.rb +34 -0
- data/lib/iam/migration/PolicyUnifier.rb +90 -0
- data/lib/iam/models/GroupConfig.rb +40 -0
- data/lib/iam/models/IamDiff.rb +132 -0
- data/lib/iam/models/PolicyConfig.rb +67 -0
- data/lib/iam/models/ResourceWithPolicy.rb +208 -0
- data/lib/iam/models/RoleConfig.rb +53 -0
- data/lib/iam/models/StatementConfig.rb +35 -0
- data/lib/iam/models/UserConfig.rb +21 -0
- data/lib/kinesis/Kinesis.rb +94 -0
- data/lib/kinesis/loader/Loader.rb +19 -0
- data/lib/kinesis/manager/Manager.rb +206 -0
- data/lib/kinesis/models/StreamConfig.rb +75 -0
- data/lib/kinesis/models/StreamDiff.rb +58 -0
- data/lib/lambda/Lambda.rb +41 -0
- data/lib/route53/loader/Loader.rb +32 -0
- data/lib/route53/manager/Manager.rb +241 -0
- data/lib/route53/models/AliasTarget.rb +86 -0
- data/lib/route53/models/RecordConfig.rb +178 -0
- data/lib/route53/models/RecordDiff.rb +140 -0
- data/lib/route53/models/Vpc.rb +24 -0
- data/lib/route53/models/ZoneConfig.rb +156 -0
- data/lib/route53/models/ZoneDiff.rb +118 -0
- data/lib/s3/S3.rb +89 -0
- data/lib/s3/loader/Loader.rb +66 -0
- data/lib/s3/manager/Manager.rb +296 -0
- data/lib/s3/models/BucketConfig.rb +321 -0
- data/lib/s3/models/BucketDiff.rb +167 -0
- data/lib/s3/models/GrantConfig.rb +189 -0
- data/lib/s3/models/GrantDiff.rb +50 -0
- data/lib/s3/models/LifecycleConfig.rb +142 -0
- data/lib/s3/models/LifecycleDiff.rb +46 -0
- data/lib/s3/models/LoggingConfig.rb +81 -0
- data/lib/s3/models/NotificationConfig.rb +157 -0
- data/lib/s3/models/NotificationDiff.rb +62 -0
- data/lib/s3/models/ReplicationConfig.rb +133 -0
- data/lib/s3/models/ReplicationDiff.rb +60 -0
- data/lib/s3/models/WebsiteConfig.rb +107 -0
- data/lib/security/SecurityGroups.rb +39 -0
- data/lib/security/loader/Loader.rb +94 -0
- data/lib/security/manager/Manager.rb +246 -0
- data/lib/security/models/RuleConfig.rb +161 -0
- data/lib/security/models/RuleDiff.rb +72 -0
- data/lib/security/models/RuleMigration.rb +127 -0
- data/lib/security/models/SecurityGroupConfig.rb +172 -0
- data/lib/security/models/SecurityGroupDiff.rb +112 -0
- data/lib/sns/SNS.rb +40 -0
- data/lib/sqs/SQS.rb +62 -0
- data/lib/sqs/loader/Loader.rb +34 -0
- data/lib/sqs/manager/Manager.rb +128 -0
- data/lib/sqs/models/DeadLetterConfig.rb +70 -0
- data/lib/sqs/models/DeadLetterDiff.rb +35 -0
- data/lib/sqs/models/QueueConfig.rb +115 -0
- data/lib/sqs/models/QueueDiff.rb +89 -0
- data/lib/util/Colors.rb +111 -0
- data/lib/util/StatusCodes.rb +51 -0
- data/lib/vpc/loader/Loader.rb +73 -0
- data/lib/vpc/manager/Manager.rb +954 -0
- data/lib/vpc/models/AclEntryConfig.rb +150 -0
- data/lib/vpc/models/AclEntryDiff.rb +54 -0
- data/lib/vpc/models/DhcpConfig.rb +100 -0
- data/lib/vpc/models/DhcpDiff.rb +90 -0
- data/lib/vpc/models/EndpointConfig.rb +76 -0
- data/lib/vpc/models/EndpointDiff.rb +69 -0
- data/lib/vpc/models/NetworkAclConfig.rb +87 -0
- data/lib/vpc/models/NetworkAclDiff.rb +116 -0
- data/lib/vpc/models/RouteConfig.rb +82 -0
- data/lib/vpc/models/RouteDiff.rb +50 -0
- data/lib/vpc/models/RouteTableConfig.rb +92 -0
- data/lib/vpc/models/RouteTableDiff.rb +101 -0
- data/lib/vpc/models/SubnetConfig.rb +113 -0
- data/lib/vpc/models/SubnetDiff.rb +78 -0
- data/lib/vpc/models/VpcConfig.rb +173 -0
- data/lib/vpc/models/VpcDiff.rb +315 -0
- data/rakefile.rb +8 -0
- metadata +245 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require "common/models/Diff"
|
|
2
|
+
require "util/Colors"
|
|
3
|
+
|
|
4
|
+
module Cumulus
|
|
5
|
+
module SecurityGroups
|
|
6
|
+
# Public: The types of changes that can be made to security group rules
|
|
7
|
+
module RuleChange
|
|
8
|
+
include Common::DiffChange
|
|
9
|
+
|
|
10
|
+
REMOVED = Common::DiffChange::next_change_id
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Public: Represents a single difference between local rule configuration and AWS
|
|
14
|
+
# configuration of security group rules
|
|
15
|
+
class RuleDiff < Common::Diff
|
|
16
|
+
include RuleChange
|
|
17
|
+
|
|
18
|
+
# Public: Static method that will produce a diff that contains an added rule
|
|
19
|
+
#
|
|
20
|
+
# local - the local configuration that was added
|
|
21
|
+
#
|
|
22
|
+
# Returns the diff
|
|
23
|
+
def RuleDiff.added(local)
|
|
24
|
+
RuleDiff.new(ADD, nil, local)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Public: Static method that will produce a diff that contains a removed rule
|
|
28
|
+
#
|
|
29
|
+
# aws - the aws configuration that was removed
|
|
30
|
+
#
|
|
31
|
+
# Returns the diff
|
|
32
|
+
def RuleDiff.removed(aws)
|
|
33
|
+
RuleDiff.new(REMOVED, aws)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_s
|
|
37
|
+
case @type
|
|
38
|
+
when ADD
|
|
39
|
+
Colors.added("#{to_readable(local)}")
|
|
40
|
+
when REMOVED
|
|
41
|
+
Colors.removed("#{to_readable(aws)}")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Internal: Produce a human readable string from a config hash
|
|
48
|
+
#
|
|
49
|
+
# config - the config to process
|
|
50
|
+
#
|
|
51
|
+
# Returns the human readable string
|
|
52
|
+
def to_readable(config)
|
|
53
|
+
# yes, for real, AWS returns the STRING "-1" if all protocols are allowed
|
|
54
|
+
protocol = if config.protocol == "-1" then "All" else config.protocol end
|
|
55
|
+
allowed = (config.security_groups + config.subnets).join(", ")
|
|
56
|
+
|
|
57
|
+
temp = "Allowed: #{allowed}, Protocol: #{protocol}, "
|
|
58
|
+
if protocol.downcase == "icmp"
|
|
59
|
+
temp << "Type: #{config.from}, Code: #{config.to}"
|
|
60
|
+
elsif config.from != config.to
|
|
61
|
+
temp << "Ports: #{config.from}-#{config.to}"
|
|
62
|
+
elsif config.from.nil?
|
|
63
|
+
temp << "Ports: All"
|
|
64
|
+
else
|
|
65
|
+
temp << "Port: #{config.from}"
|
|
66
|
+
end
|
|
67
|
+
temp
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module Cumulus
|
|
2
|
+
module SecurityGroups
|
|
3
|
+
# A class used to migrate RuleConfigs
|
|
4
|
+
class RuleMigration
|
|
5
|
+
|
|
6
|
+
attr_reader :ports
|
|
7
|
+
attr_reader :icmp_type
|
|
8
|
+
attr_reader :icmp_code
|
|
9
|
+
attr_reader :protocol
|
|
10
|
+
attr_reader :security_groups
|
|
11
|
+
attr_reader :subnets
|
|
12
|
+
|
|
13
|
+
# Public: Static method that will produce a RuleMigration from a RuleConfig
|
|
14
|
+
#
|
|
15
|
+
# rule_config - the RuleConfig to create from
|
|
16
|
+
#
|
|
17
|
+
# Returns the corresponding RuleMigration
|
|
18
|
+
def self.from_rule_config(rule_config)
|
|
19
|
+
ports = if (rule_config.from.nil? and rule_config.to.nil?) or rule_config.protocol == "icmp"
|
|
20
|
+
nil
|
|
21
|
+
else
|
|
22
|
+
if rule_config.from == rule_config.to
|
|
23
|
+
[rule_config.from]
|
|
24
|
+
else
|
|
25
|
+
["#{rule_config.from}-#{rule_config.to}"]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
icmp_type = if rule_config.protocol == "icmp" then rule_config.from end
|
|
30
|
+
icmp_code = if rule_config.protocol == "icmp" then rule_config.to end
|
|
31
|
+
|
|
32
|
+
# we're gonna replace any "0.0.0.0/0" with all to educate users on subnets.json
|
|
33
|
+
subnets = rule_config.subnets.map do |subnet|
|
|
34
|
+
if subnet == "0.0.0.0/0"
|
|
35
|
+
"all"
|
|
36
|
+
else
|
|
37
|
+
subnet
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
RuleMigration.new(
|
|
42
|
+
ports,
|
|
43
|
+
rule_config.protocol,
|
|
44
|
+
icmp_type,
|
|
45
|
+
icmp_code,
|
|
46
|
+
rule_config.security_groups,
|
|
47
|
+
subnets
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Public: Constructor.
|
|
52
|
+
#
|
|
53
|
+
# ports - an array of the ports to put into cumulus config, or nil for all
|
|
54
|
+
# protocol - the protocol for the rule
|
|
55
|
+
# icmp_type - if protocol is icmp, the icmp type
|
|
56
|
+
# icmp_code - if protocol is icmp, the icmp code
|
|
57
|
+
# security_groups - an array of security group names for the rule, or nil if there are no security groups
|
|
58
|
+
# subnets - an array of subnets to include in the rule, or nil if there are no subnets
|
|
59
|
+
def initialize(ports, protocol, icmp_type, icmp_code, security_groups, subnets)
|
|
60
|
+
@ports = ports
|
|
61
|
+
@protocol = protocol
|
|
62
|
+
@icmp_type = icmp_type
|
|
63
|
+
@icmp_code = icmp_code
|
|
64
|
+
@security_groups = security_groups
|
|
65
|
+
@subnets = subnets
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Public: Get the configuration as a hash for migration
|
|
69
|
+
#
|
|
70
|
+
# Returns the hash
|
|
71
|
+
def hash
|
|
72
|
+
{
|
|
73
|
+
"security-groups" => @security_groups,
|
|
74
|
+
"protocol" => @protocol,
|
|
75
|
+
"ports" => @ports,
|
|
76
|
+
"icmp-type" => @icmp_type,
|
|
77
|
+
"icmp-code" => @icmp_code,
|
|
78
|
+
"subnets" => @subnets,
|
|
79
|
+
}.reject { |k, v| v.nil? }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Public: Combine two RuleMigrations by combining allowed entities (security group or subnet).
|
|
83
|
+
#
|
|
84
|
+
# other - the other RuleMigration to combine with this one
|
|
85
|
+
#
|
|
86
|
+
# Returns the a new RuleMigration with this RuleMigration's ports and protocol, and
|
|
87
|
+
# the allowed entities of both RuleMigrations concatenated together
|
|
88
|
+
def combine_allowed(other)
|
|
89
|
+
RuleMigration.new(
|
|
90
|
+
@ports,
|
|
91
|
+
@protocol,
|
|
92
|
+
@icmp_type,
|
|
93
|
+
@icmp_code,
|
|
94
|
+
@security_groups + other.security_groups,
|
|
95
|
+
@subnets + other.subnets
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Public: Combine two RuleMigrations by combining ports. If both of the RuleMigrations
|
|
100
|
+
# have nil ports, they will be combined, but if only one does, an array containing
|
|
101
|
+
# both RuleMigrations (unchanged) will be returned
|
|
102
|
+
#
|
|
103
|
+
# other - the other RuleMigration to combine with this one
|
|
104
|
+
#
|
|
105
|
+
# Returns a new RuleMigration with this RuleMigration's allowed entities and the combined port
|
|
106
|
+
# or an array of the two original RuleMigrations
|
|
107
|
+
def combine_ports(other)
|
|
108
|
+
# In this case, they should be identical, we just return self
|
|
109
|
+
if !@ports and !other.ports
|
|
110
|
+
self
|
|
111
|
+
# at this point we're guaranteed that if one of the ports is nil, the other is not
|
|
112
|
+
elsif @ports.nil? or other.ports.nil?
|
|
113
|
+
[self, other]
|
|
114
|
+
else
|
|
115
|
+
RuleMigration.new(
|
|
116
|
+
@ports + other.ports,
|
|
117
|
+
@protocol,
|
|
118
|
+
@icmp_type,
|
|
119
|
+
@icmp_code,
|
|
120
|
+
@security_groups,
|
|
121
|
+
@subnets
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
require "conf/Configuration"
|
|
2
|
+
require "security/loader/Loader"
|
|
3
|
+
require "security/models/RuleConfig"
|
|
4
|
+
require "security/models/RuleDiff"
|
|
5
|
+
require "security/models/RuleMigration"
|
|
6
|
+
require "security/models/SecurityGroupDiff"
|
|
7
|
+
|
|
8
|
+
require "json"
|
|
9
|
+
|
|
10
|
+
module Cumulus
|
|
11
|
+
module SecurityGroups
|
|
12
|
+
# Public: An object representing configuration for a security group
|
|
13
|
+
class SecurityGroupConfig
|
|
14
|
+
|
|
15
|
+
attr_reader :description
|
|
16
|
+
attr_reader :includes
|
|
17
|
+
attr_reader :inbound
|
|
18
|
+
attr_reader :name
|
|
19
|
+
attr_reader :outbound
|
|
20
|
+
attr_reader :tags
|
|
21
|
+
attr_reader :vpc_id
|
|
22
|
+
|
|
23
|
+
# Public: Constructor.
|
|
24
|
+
#
|
|
25
|
+
# name - the name of the security group
|
|
26
|
+
# vpc_id - the id of the vpc the security group belongs in
|
|
27
|
+
# json - a hash containing the JSON configuration for the security group
|
|
28
|
+
def initialize(name, vpc_id, json = nil)
|
|
29
|
+
@name = name
|
|
30
|
+
@vpc_id = vpc_id
|
|
31
|
+
if !json.nil?
|
|
32
|
+
@description = if !json["description"].nil? then json["description"] else "" end
|
|
33
|
+
@tags = if !json["tags"].nil? then json["tags"] else {} end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
includes = (json["rules"]["includes"] || []).map { |rule| Loader.rule(rule) }
|
|
37
|
+
inbound_includes = includes.reduce([]) { |sofar, inc| sofar + (inc["inbound"] || []) }.flatten.compact
|
|
38
|
+
outbound_includes = includes.reduce([]) { |sofar, inc| sofar + (inc["outbound"] || []) }.flatten.compact
|
|
39
|
+
|
|
40
|
+
combined_inbound = (json["rules"]["inbound"] || []) + inbound_includes
|
|
41
|
+
@inbound = combined_inbound.map(&RuleConfig.method(:expand_ports)).flatten
|
|
42
|
+
|
|
43
|
+
combined_outbound = (json["rules"]["outbound"] || []) + outbound_includes
|
|
44
|
+
@outbound = if !json["rules"]["outbound"].nil?
|
|
45
|
+
combined_outbound.map(&RuleConfig.method(:expand_ports)).flatten
|
|
46
|
+
else
|
|
47
|
+
if Configuration.instance.security.outbound_default_all_allowed
|
|
48
|
+
[RuleConfig.allow_all]
|
|
49
|
+
else
|
|
50
|
+
outbound_includes
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Public: Produce an array of the differences between this local configuration and the
|
|
57
|
+
# configuration in AWS
|
|
58
|
+
#
|
|
59
|
+
# aws - the aws resource
|
|
60
|
+
#
|
|
61
|
+
# Returns an array of the SecurityGroupDiffs that were found
|
|
62
|
+
def diff(aws)
|
|
63
|
+
diffs = []
|
|
64
|
+
|
|
65
|
+
if @description != aws.description
|
|
66
|
+
diffs << SecurityGroupDiff.new(SecurityGroupChange::DESCRIPTION, aws, self)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if @tags != Hash[aws.tags.map { |t| [t.key, t.value] }]
|
|
70
|
+
diffs << SecurityGroupDiff.new(SecurityGroupChange::TAGS, aws, self)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
inbound_diffs = diff_rules(@inbound, aws.ip_permissions)
|
|
74
|
+
if !inbound_diffs.empty?
|
|
75
|
+
diffs << SecurityGroupDiff.inbound(aws, self, inbound_diffs)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
outbound_diffs = diff_rules(@outbound, aws.ip_permissions_egress)
|
|
79
|
+
if !outbound_diffs.empty?
|
|
80
|
+
diffs << SecurityGroupDiff.outbound(aws, self, outbound_diffs)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
diffs
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Public: Populate this SecurityGroupConfig from an AWS resource
|
|
87
|
+
#
|
|
88
|
+
# aws - the aws resource
|
|
89
|
+
def populate!(aws)
|
|
90
|
+
@vpc_id = aws.vpc_id
|
|
91
|
+
@description = aws.description
|
|
92
|
+
@tags = Hash[aws.tags.map { |t| [t.key, t.value] }]
|
|
93
|
+
@inbound = combine_rules(aws.ip_permissions.map { |rule| RuleConfig.from_aws(rule) })
|
|
94
|
+
@outbound = combine_rules(aws.ip_permissions_egress.map { |rule| RuleConfig.from_aws(rule) })
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Public: Get the config as a prettified JSON string.
|
|
98
|
+
#
|
|
99
|
+
# Returns the JSON string
|
|
100
|
+
def pretty_json
|
|
101
|
+
JSON.pretty_generate({
|
|
102
|
+
"description" => @description,
|
|
103
|
+
"tags" => @tags,
|
|
104
|
+
"rules" => {
|
|
105
|
+
"inbound" => @inbound.map(&:hash),
|
|
106
|
+
"outbound" => @outbound.map(&:hash),
|
|
107
|
+
}
|
|
108
|
+
}.reject { |k, v| v.nil? })
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
# Internal: Determine changes in rules
|
|
114
|
+
#
|
|
115
|
+
# local_rules - the rules defined locally
|
|
116
|
+
# aws_rules - the rules in AWS
|
|
117
|
+
#
|
|
118
|
+
# Returns an array of RuleDiffs that represent differences between local and AWS configuration
|
|
119
|
+
def diff_rules(local_rules, aws_rules)
|
|
120
|
+
diffs = []
|
|
121
|
+
|
|
122
|
+
# get the aws config into a format that mirrors cumulus so we can compare
|
|
123
|
+
aws = aws_rules.map do |rule|
|
|
124
|
+
RuleConfig.from_aws(rule)
|
|
125
|
+
end
|
|
126
|
+
aws_hashes = aws.flat_map(&:hash)
|
|
127
|
+
local_hashes = local_rules.flat_map(&:hash)
|
|
128
|
+
|
|
129
|
+
diffs << local_hashes.reject { |i| aws_hashes.include?(i) }.map { |l| RuleDiff.added(RuleConfig.new(l)) }
|
|
130
|
+
diffs << aws_hashes.reject { |a| local_hashes.include?(a) }.map { |a| RuleDiff.removed(RuleConfig.new(a)) }
|
|
131
|
+
|
|
132
|
+
diffs.flatten
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Internal: Combine rules that have the same ports and security groups to create the compact version
|
|
136
|
+
# used by cumulus config.
|
|
137
|
+
#
|
|
138
|
+
# rules - an array of the rules to combine
|
|
139
|
+
#
|
|
140
|
+
# Returns an array of compact rules
|
|
141
|
+
def combine_rules(rules)
|
|
142
|
+
# separate out icmp rules
|
|
143
|
+
all_rules = rules.map(&RuleMigration.method(:from_rule_config))
|
|
144
|
+
icmp_rules = all_rules.select { |rule| rule.protocol == "icmp" }
|
|
145
|
+
|
|
146
|
+
# first we find the ones that have the same protocol and port
|
|
147
|
+
other_rules = all_rules.reject { |rule| rule.protocol == "icmp" }.group_by do |rule|
|
|
148
|
+
[rule.protocol, rule.ports]
|
|
149
|
+
# next, we combine the matching rules together
|
|
150
|
+
end.flat_map do |_, matches|
|
|
151
|
+
if matches.size == 1
|
|
152
|
+
matches
|
|
153
|
+
else
|
|
154
|
+
matches[1..-1].inject(matches[0]) { |prev, cur| prev.combine_allowed(cur) }
|
|
155
|
+
end
|
|
156
|
+
# now, try to find ones that have the same groups of allowed entities and protocol
|
|
157
|
+
end.group_by do |rule|
|
|
158
|
+
[rule.protocol, rule.security_groups, rule.subnets]
|
|
159
|
+
# finally, we'll combine ports for the matches
|
|
160
|
+
end.flat_map do |_, matches|
|
|
161
|
+
if matches.size == 1
|
|
162
|
+
matches
|
|
163
|
+
else
|
|
164
|
+
matches[1..-1].inject(matches[0]) { |prev, cur| prev.combine_ports(cur) }
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
icmp_rules + other_rules
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require "common/models/Diff"
|
|
2
|
+
require "common/models/TagsDiff"
|
|
3
|
+
require "security/models/RuleDiff"
|
|
4
|
+
require "util/Colors"
|
|
5
|
+
|
|
6
|
+
module Cumulus
|
|
7
|
+
module SecurityGroups
|
|
8
|
+
# Public: The types of changes that can be made to security groups
|
|
9
|
+
module SecurityGroupChange
|
|
10
|
+
include Common::DiffChange
|
|
11
|
+
|
|
12
|
+
DESCRIPTION = Common::DiffChange::next_change_id
|
|
13
|
+
TAGS = Common::DiffChange::next_change_id
|
|
14
|
+
INBOUND = Common::DiffChange::next_change_id
|
|
15
|
+
OUTBOUND = Common::DiffChange::next_change_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Public: Represents a single difference between local configuration and AWS configuration
|
|
19
|
+
# of security groups
|
|
20
|
+
class SecurityGroupDiff < Common::Diff
|
|
21
|
+
include SecurityGroupChange
|
|
22
|
+
include Common::TagsDiff
|
|
23
|
+
|
|
24
|
+
attr_accessor :inbound_diffs
|
|
25
|
+
attr_accessor :outbound_diffs
|
|
26
|
+
|
|
27
|
+
# Public: Static method that will produce a diff that contains changes in inbound rules
|
|
28
|
+
#
|
|
29
|
+
# aws - the aws configuration
|
|
30
|
+
# local - the local configuration
|
|
31
|
+
# inbound_diffs - the differences in inbound rules
|
|
32
|
+
#
|
|
33
|
+
# Returns the diff
|
|
34
|
+
def SecurityGroupDiff.inbound(aws, local, inbound_diffs)
|
|
35
|
+
diff = SecurityGroupDiff.new(INBOUND, aws, local)
|
|
36
|
+
diff.inbound_diffs = inbound_diffs
|
|
37
|
+
diff
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Public: Static method that will produce a diff that contains changes in outbound rules
|
|
41
|
+
#
|
|
42
|
+
# aws - the aws configuration
|
|
43
|
+
# local - the local configuration
|
|
44
|
+
# outbound_diffs - the differences in outbound rules
|
|
45
|
+
#
|
|
46
|
+
# Returns the diff
|
|
47
|
+
def SecurityGroupDiff.outbound(aws, local, outbound_diffs)
|
|
48
|
+
diff = SecurityGroupDiff.new(OUTBOUND, aws, local)
|
|
49
|
+
diff.outbound_diffs = outbound_diffs
|
|
50
|
+
diff
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def asset_type
|
|
54
|
+
"Security group"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def aws_name
|
|
58
|
+
@aws.vpc_group_name
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def diff_string
|
|
62
|
+
case @type
|
|
63
|
+
when DESCRIPTION
|
|
64
|
+
[
|
|
65
|
+
"Description:",
|
|
66
|
+
Colors.aws_changes("\tAWS - #{@aws.description}"),
|
|
67
|
+
Colors.local_changes("\tLocal - #{@local.description}"),
|
|
68
|
+
"\tUnfortunately, AWS's SDK does not allow updating the description."
|
|
69
|
+
].join("\n")
|
|
70
|
+
when INBOUND
|
|
71
|
+
lines = ["Inbound rules:"]
|
|
72
|
+
lines << inbound_diffs.map { |d| "\t#{d}" }
|
|
73
|
+
lines.flatten.join("\n")
|
|
74
|
+
when OUTBOUND
|
|
75
|
+
lines = ["Outbound rules:"]
|
|
76
|
+
lines << outbound_diffs.map { |d| "\t#{d}" }
|
|
77
|
+
lines.flatten.join("\n")
|
|
78
|
+
when TAGS
|
|
79
|
+
tags_diff_string
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Public: Get the inbound rules to add
|
|
84
|
+
#
|
|
85
|
+
# Returns the added rules
|
|
86
|
+
def added_inbounds
|
|
87
|
+
inbound_diffs.reject { |i| i.type == RuleChange::REMOVED }.map(&:local)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Public: Get the inbound rules to remove
|
|
91
|
+
#
|
|
92
|
+
# Returns the removed rules
|
|
93
|
+
def removed_inbounds
|
|
94
|
+
inbound_diffs.reject { |i| i.type == RuleChange::ADD }.map(&:aws)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Public: Get the outbound rules to add
|
|
98
|
+
#
|
|
99
|
+
# Returns the added rules
|
|
100
|
+
def added_outbounds
|
|
101
|
+
outbound_diffs.reject { |o| o.type == RuleChange::REMOVED }.map(&:local)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Public: Get the outbound rules to remove
|
|
105
|
+
#
|
|
106
|
+
# Returns the removed rules
|
|
107
|
+
def removed_outbounds
|
|
108
|
+
outbound_diffs.reject { |o| o.type == RuleChange::ADD }.map(&:aws)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|