sgviz 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5fb5e9336b59957898dee4d98ae5e9f25a04b49
4
+ data.tar.gz: 38da4f2f906e141d05e4e99f01dfb11de18f1605
5
+ SHA512:
6
+ metadata.gz: 908045418f324d4094d2b69c681cf189235a8d3d9f5daf2fe9ed75291e12f16524cde17b78ccd0666778c8b2049e1ee47518ddead734975847e9127934b49461
7
+ data.tar.gz: 2ebcda6849078ddca64d553a8467a06f7da75d53148a764fea7d23288d8bfa00b6ff3a55220d6ba92563404ac7147e35bbad7ab8dfc870ac94a7f9721b2e2af2
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ vendor
16
+ result.json
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sgviz.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 y13i
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # Sgviz
2
+
3
+ A visualization tool for AWS VPC Security Groups.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'sgviz'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install sgviz
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```bash
28
+ $ sgviz generate --output-path myvpc --region ap-northeast-1 --vpc-ids vpc-146fad71
29
+ ```
30
+
31
+ will generate
32
+
33
+ ![myvpc](docs/images/1.png)
34
+
35
+ If you're using OSX, run `sgviz open` to view the graph instantly.
36
+
37
+ Run `sgviz help` to view more usage.
38
+
39
+ ## CloudFormation Template
40
+
41
+ You can create example stack using bundled CloudFormation template.
42
+
43
+ ```bash
44
+ $ aws cloudformation create-stack --stack-name example --template-body file:////path/to/this/repo/docs/cfn/example.json
45
+ ```
46
+
47
+ Or use [Kumogata](https://github.com/winebarrel/kumogata), powerful Ruby-CFn integration tool.
48
+
49
+ ```bash
50
+ $ kumogata create docs/cfn/example.rb example
51
+ ```
52
+
53
+ ## TODO, Known Bugs
54
+
55
+ * Bug: Problem with outbound edges (duplicate with inbound?).
56
+ * TODO: Internal IP address nodes.
57
+ * TODO: VPC Peerings.
58
+ * TODO: Add spec. (No test code now. Sorry.)
59
+ * TODO: Integrate EC2/ELB/RDS/ElastiCache/Redshift components in graph.
60
+ * etc...
61
+
62
+ ## Contributing
63
+
64
+ 1. Fork it ( https://github.com/y13i/sgviz/fork )
65
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
66
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
67
+ 4. Push to the branch (`git push origin my-new-feature`)
68
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/sgviz ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "sgviz"
4
+
5
+ Sgviz::CLI.start
@@ -0,0 +1,222 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Description": "Sgviz example security group set template (Donburi version).\n",
4
+ "Resources": {
5
+ "Vpc": {
6
+ "Type": "AWS::EC2::VPC",
7
+ "Properties": {
8
+ "CidrBlock": "10.0.0.0/16"
9
+ }
10
+ },
11
+ "ManageSecurityGroup": {
12
+ "Type": "AWS::EC2::SecurityGroup",
13
+ "Properties": {
14
+ "GroupDescription": "Security group for manage role EC2 instances.",
15
+ "VpcId": {
16
+ "Ref": "Vpc"
17
+ },
18
+ "SecurityGroupIngress": [
19
+ {
20
+ "CidrIp": "123.45.67.89/32",
21
+ "IpProtocol": "tcp",
22
+ "FromPort": "22",
23
+ "ToPort": "22"
24
+ },
25
+ {
26
+ "CidrIp": "123.45.67.89/32",
27
+ "IpProtocol": "tcp",
28
+ "FromPort": "80",
29
+ "ToPort": "80"
30
+ },
31
+ {
32
+ "CidrIp": "123.45.67.89/32",
33
+ "IpProtocol": "tcp",
34
+ "FromPort": "443",
35
+ "ToPort": "443"
36
+ },
37
+ {
38
+ "CidrIp": "234.56.78.90/32",
39
+ "IpProtocol": "tcp",
40
+ "FromPort": "22",
41
+ "ToPort": "22"
42
+ },
43
+ {
44
+ "CidrIp": "234.56.78.90/32",
45
+ "IpProtocol": "tcp",
46
+ "FromPort": "80",
47
+ "ToPort": "80"
48
+ },
49
+ {
50
+ "CidrIp": "234.56.78.90/32",
51
+ "IpProtocol": "tcp",
52
+ "FromPort": "443",
53
+ "ToPort": "443"
54
+ }
55
+ ],
56
+ "Tags": [
57
+ {
58
+ "Key": "Name",
59
+ "Value": "manage"
60
+ }
61
+ ]
62
+ }
63
+ },
64
+ "AppLoadBalancerSecurityGroup": {
65
+ "Type": "AWS::EC2::SecurityGroup",
66
+ "Properties": {
67
+ "GroupDescription": "Security group for application load balancer.",
68
+ "VpcId": {
69
+ "Ref": "Vpc"
70
+ },
71
+ "SecurityGroupIngress": [
72
+ {
73
+ "CidrIp": "0.0.0.0/0",
74
+ "IpProtocol": "tcp",
75
+ "FromPort": "80",
76
+ "ToPort": "80"
77
+ },
78
+ {
79
+ "CidrIp": "0.0.0.0/0",
80
+ "IpProtocol": "tcp",
81
+ "FromPort": "443",
82
+ "ToPort": "443"
83
+ }
84
+ ],
85
+ "Tags": [
86
+ {
87
+ "Key": "Name",
88
+ "Value": "app_load_balancer"
89
+ }
90
+ ]
91
+ }
92
+ },
93
+ "AppSecurityGroup": {
94
+ "Type": "AWS::EC2::SecurityGroup",
95
+ "Properties": {
96
+ "GroupDescription": "Security group for application EC2 instances.",
97
+ "VpcId": {
98
+ "Ref": "Vpc"
99
+ },
100
+ "SecurityGroupIngress": [
101
+ {
102
+ "SourceSecurityGroupId": {
103
+ "Ref": "AppLoadBalancerSecurityGroup"
104
+ },
105
+ "IpProtocol": "tcp",
106
+ "FromPort": "80",
107
+ "ToPort": "80"
108
+ },
109
+ {
110
+ "SourceSecurityGroupId": {
111
+ "Ref": "ManageSecurityGroup"
112
+ },
113
+ "IpProtocol": "tcp",
114
+ "FromPort": "22",
115
+ "ToPort": "22"
116
+ },
117
+ {
118
+ "SourceSecurityGroupId": {
119
+ "Ref": "ManageSecurityGroup"
120
+ },
121
+ "IpProtocol": "tcp",
122
+ "FromPort": "10050",
123
+ "ToPort": "10050"
124
+ }
125
+ ],
126
+ "Tags": [
127
+ {
128
+ "Key": "Name",
129
+ "Value": "app"
130
+ }
131
+ ]
132
+ }
133
+ },
134
+ "Port10051IngressFromAppToManage": {
135
+ "Type": "AWS::EC2::SecurityGroupIngress",
136
+ "Properties": {
137
+ "GroupId": {
138
+ "Ref": "ManageSecurityGroup"
139
+ },
140
+ "SourceSecurityGroupId": {
141
+ "Ref": "AppSecurityGroup"
142
+ },
143
+ "IpProtocol": "tcp",
144
+ "FromPort": "10051",
145
+ "ToPort": "10051"
146
+ }
147
+ },
148
+ "RedisSecurityGroup": {
149
+ "Type": "AWS::EC2::SecurityGroup",
150
+ "Properties": {
151
+ "GroupDescription": "Security group for ElastiCache Redis clusters.",
152
+ "VpcId": {
153
+ "Ref": "Vpc"
154
+ },
155
+ "SecurityGroupIngress": [
156
+ {
157
+ "SourceSecurityGroupId": {
158
+ "Ref": "ManageSecurityGroup"
159
+ },
160
+ "IpProtocol": "tcp",
161
+ "FromPort": "6379",
162
+ "ToPort": "6379"
163
+ },
164
+ {
165
+ "SourceSecurityGroupId": {
166
+ "Ref": "AppSecurityGroup"
167
+ },
168
+ "IpProtocol": "tcp",
169
+ "FromPort": "6379",
170
+ "ToPort": "6379"
171
+ }
172
+ ],
173
+ "Tags": [
174
+ {
175
+ "Key": "Name",
176
+ "Value": "redis"
177
+ }
178
+ ]
179
+ }
180
+ },
181
+ "MysqlSecurityGroup": {
182
+ "Type": "AWS::EC2::SecurityGroup",
183
+ "Properties": {
184
+ "GroupDescription": "Security group for RDS MySQL DB instances.",
185
+ "VpcId": {
186
+ "Ref": "Vpc"
187
+ },
188
+ "SecurityGroupIngress": [
189
+ {
190
+ "SourceSecurityGroupId": {
191
+ "Ref": "ManageSecurityGroup"
192
+ },
193
+ "IpProtocol": "tcp",
194
+ "FromPort": "3306",
195
+ "ToPort": "3306"
196
+ },
197
+ {
198
+ "SourceSecurityGroupId": {
199
+ "Ref": "AppSecurityGroup"
200
+ },
201
+ "IpProtocol": "tcp",
202
+ "FromPort": "3306",
203
+ "ToPort": "3306"
204
+ }
205
+ ],
206
+ "Tags": [
207
+ {
208
+ "Key": "Name",
209
+ "Value": "mysql"
210
+ }
211
+ ]
212
+ }
213
+ }
214
+ },
215
+ "Outputs": {
216
+ "Vpc": {
217
+ "Value": {
218
+ "Ref": "Vpc"
219
+ }
220
+ }
221
+ }
222
+ }
@@ -0,0 +1,177 @@
1
+ AWSTemplateFormatVersion "2010-09-09"
2
+
3
+ Description <<-EOS.undent
4
+ Sgviz example security group set template (Donburi version).
5
+ EOS
6
+
7
+ Resources do
8
+ Vpc do
9
+ Type "AWS::EC2::VPC"
10
+
11
+ Properties do
12
+ CidrBlock "10.0.0.0/16"
13
+ end
14
+ end
15
+
16
+ ManageSecurityGroup do
17
+ Type "AWS::EC2::SecurityGroup"
18
+
19
+ Properties do
20
+ GroupDescription "Security group for manage role EC2 instances."
21
+ VpcId {Ref "Vpc"}
22
+
23
+ SecurityGroupIngress(
24
+ ["123.45.67.89/32", "234.56.78.90/32", ].product([22, 80, 443]).map do |my_ip, port|
25
+ _{
26
+ CidrIp my_ip
27
+ IpProtocol "tcp"
28
+ FromPort port
29
+ ToPort port
30
+ }
31
+ end
32
+ )
33
+
34
+ Tags [
35
+ _{
36
+ Key "Name"
37
+ Value "manage"
38
+ }
39
+ ]
40
+ end
41
+ end
42
+
43
+ AppLoadBalancerSecurityGroup do
44
+ Type "AWS::EC2::SecurityGroup"
45
+
46
+ Properties do
47
+ GroupDescription "Security group for application load balancer."
48
+ VpcId {Ref "Vpc"}
49
+
50
+ SecurityGroupIngress(
51
+ [80, 443].map do |port|
52
+ _{
53
+ CidrIp "0.0.0.0/0"
54
+ IpProtocol "tcp"
55
+ FromPort port
56
+ ToPort port
57
+ }
58
+ end
59
+ )
60
+
61
+ Tags [
62
+ _{
63
+ Key "Name"
64
+ Value "app_load_balancer"
65
+ }
66
+ ]
67
+ end
68
+ end
69
+
70
+ AppSecurityGroup do
71
+ Type "AWS::EC2::SecurityGroup"
72
+
73
+ Properties do
74
+ GroupDescription "Security group for application EC2 instances."
75
+ VpcId {Ref "Vpc"}
76
+
77
+ SecurityGroupIngress [
78
+ _{
79
+ SourceSecurityGroupId {Ref "AppLoadBalancerSecurityGroup"}
80
+ IpProtocol "tcp"
81
+ FromPort 80
82
+ ToPort 80
83
+ },
84
+
85
+ *[22, 10050].map do |port|
86
+ _{
87
+ SourceSecurityGroupId {Ref "ManageSecurityGroup"}
88
+ IpProtocol "tcp"
89
+ FromPort port
90
+ ToPort port
91
+ }
92
+ end
93
+ ]
94
+
95
+ Tags [
96
+ _{
97
+ Key "Name"
98
+ Value "app"
99
+ }
100
+ ]
101
+ end
102
+ end
103
+
104
+ Port10051IngressFromAppToManage do
105
+ Type "AWS::EC2::SecurityGroupIngress"
106
+
107
+ Properties do
108
+ GroupId {Ref "ManageSecurityGroup"}
109
+ SourceSecurityGroupId {Ref "AppSecurityGroup"}
110
+ IpProtocol "tcp"
111
+ FromPort 10051
112
+ ToPort 10051
113
+ end
114
+ end
115
+
116
+ RedisSecurityGroup do
117
+ Type "AWS::EC2::SecurityGroup"
118
+
119
+ Properties do
120
+ GroupDescription "Security group for ElastiCache Redis clusters."
121
+ VpcId {Ref "Vpc"}
122
+
123
+ SecurityGroupIngress(
124
+ ["Manage", "App"].map do |role|
125
+ _{
126
+ SourceSecurityGroupId {Ref "#{role}SecurityGroup"}
127
+ IpProtocol "tcp"
128
+ FromPort 6379
129
+ ToPort 6379
130
+ }
131
+ end
132
+ )
133
+
134
+ Tags [
135
+ _{
136
+ Key "Name"
137
+ Value "redis"
138
+ }
139
+ ]
140
+ end
141
+ end
142
+
143
+ MysqlSecurityGroup do
144
+ Type "AWS::EC2::SecurityGroup"
145
+
146
+ Properties do
147
+ GroupDescription "Security group for RDS MySQL DB instances."
148
+ VpcId {Ref "Vpc"}
149
+
150
+ SecurityGroupIngress(
151
+ ["Manage", "App"].map do |role|
152
+ _{
153
+ SourceSecurityGroupId {Ref "#{role}SecurityGroup"}
154
+ IpProtocol "tcp"
155
+ FromPort 3306
156
+ ToPort 3306
157
+ }
158
+ end
159
+ )
160
+
161
+ Tags [
162
+ _{
163
+ Key "Name"
164
+ Value "mysql"
165
+ }
166
+ ]
167
+ end
168
+ end
169
+ end
170
+
171
+ Outputs do
172
+ Vpc do
173
+ Value do
174
+ Ref "Vpc"
175
+ end
176
+ end
177
+ end
data/docs/images/1.png ADDED
Binary file
data/lib/sgviz/cli.rb ADDED
@@ -0,0 +1,80 @@
1
+ require "thor"
2
+
3
+ class Sgviz::CLI < Thor
4
+ class_option :profile,
5
+ desc: "Load credentials by profile name from shared credentials file (~/.aws/credentials).",
6
+ aliases: [:p]
7
+
8
+ class_option :access_key_id,
9
+ desc: "AWS access key id.",
10
+ aliases: [:k]
11
+
12
+ class_option :secret_access_key,
13
+ desc: "AWS secret access key.",
14
+ aliases: [:s]
15
+
16
+ class_option :region,
17
+ desc: "AWS region.",
18
+ aliases: [:r]
19
+
20
+ class_option :format,
21
+ desc: "Output file format",
22
+ aliases: [:f],
23
+ default: "png"
24
+
25
+ class_option :output_path,
26
+ desc: "Output file path.",
27
+ aliases: [:output, :o]
28
+
29
+ class_option :vpc_ids,
30
+ desc: "AWS VPC IDs (If specified, graph will include security groups in the VPCs).",
31
+ aliases: [:vpcs, :vpc, :v],
32
+ type: :array
33
+
34
+ class_option :inbound_only,
35
+ desc: "If specified, graph will exclude outbound rules.",
36
+ type: :boolean,
37
+ default: true
38
+
39
+ class_option :global_label,
40
+ desc: "Label of the diagram.",
41
+ default: ""
42
+
43
+ class_option :fontname,
44
+ desc: "Font name used on labels.",
45
+ default: "Futura"
46
+
47
+ class_option :fontsize,
48
+ desc: "Font size used on labels.",
49
+ type: :numeric,
50
+ default: 15
51
+
52
+ desc "version", "Puts sgviz version."
53
+ def version
54
+ puts Sgviz::VERSION
55
+ end
56
+
57
+ desc "open", "Generate and open a graph file."
58
+ method_option :output_path, required: true
59
+ def open
60
+ unless system "which open > /dev/null"
61
+ abort "`open` command not found."
62
+ end
63
+
64
+ generate
65
+ system "open #{options.output_path}.#{options.format}"
66
+ end
67
+
68
+ desc "generate", "Generate a graph file."
69
+ method_option :output_path, required: true
70
+ def generate
71
+ generator.generate
72
+ puts "Graph generated to `#{options.output_path}.#{options.format}`."
73
+ end
74
+
75
+ private
76
+
77
+ def generator
78
+ @generator ||= Sgviz::Generator.new :G, :digraph, options
79
+ end
80
+ end
@@ -0,0 +1,251 @@
1
+ require "gviz"
2
+ require "aws-sdk-resources"
3
+
4
+ class Sgviz::Generator < Gviz
5
+ def initialize name = :G, type = :digraph, options = {}
6
+ @options = options
7
+ super(name, type)
8
+ end
9
+
10
+ def subgraph(name=:"cluster#{subgraphs.size}", &blk)
11
+ self.class.new(name, :subgraph, options).tap do |graph|
12
+ subgraphs << graph
13
+ graph.instance_eval &blk
14
+ end
15
+ end
16
+
17
+ def generate
18
+ global(
19
+ layout: "dot",
20
+ label: options.global_label,
21
+ labelloc: "b",
22
+ fontsize: options.fontsize,
23
+ fontname: options.fontname,
24
+ fontcolor: "#54523F",
25
+ margin: 20,
26
+ )
27
+
28
+ nodes(
29
+ fontsize: options.fontsize,
30
+ fontname: options.fontname,
31
+ )
32
+
33
+ vpc_security_groups.each do |vpc_id, security_groups|
34
+ security_groups.each do |security_group|
35
+ subgraph :clusterAWS do
36
+ global(
37
+ label: aws_configuration[:region],
38
+ labelloc: "b",
39
+ style: "rounded",
40
+ color: "#999999",
41
+ fontsize: options.fontsize,
42
+ fontname: options.fontname,
43
+ fontcolor: "#54523F",
44
+ margin: 20,
45
+ )
46
+
47
+ node :aws,
48
+ label: "",
49
+ image: "#{__dir__}/images/aws.png",
50
+ peripheries: 0,
51
+ fixedsize: true,
52
+ imagescale: true,
53
+ shape: "circle",
54
+ width: 1.5
55
+
56
+ subgraph :"cluster#{vpc_id[4..-1]}" do
57
+ global(
58
+ label: vpc_id,
59
+ labelloc: "b",
60
+ style: "rounded",
61
+ color: "#999999",
62
+ fontsize: options.fontsize,
63
+ fontname: options.fontname,
64
+ fontcolor: "#54523F",
65
+ margin: 20,
66
+ )
67
+
68
+ node vpc_id.to_id,
69
+ label: "",
70
+ image: "#{__dir__}/images/vpc.png",
71
+ peripheries: 0,
72
+ fixedsize: true,
73
+ imagescale: true,
74
+ shape: "circle",
75
+ width: 1.5
76
+
77
+ name_tag = security_group.tags.find {|tag| tag.key == "Name"}
78
+
79
+ node security_group.id.to_id,
80
+ shape: "note",
81
+ style: "filled",
82
+ color: "#EDEAD2",
83
+ fillcolor: "#EDEAD2",
84
+ label: "#{name_tag ? name_tag.value : security_group.group_name}\n(#{security_group.id})",
85
+ fontsize: options.fontsize,
86
+ fontname: options.fontname,
87
+ fontcolor: "#54523F",
88
+ margin: 0.2
89
+ end
90
+ end
91
+
92
+ security_group.ip_permissions.each do |ip_permission|
93
+ to = security_group.id.to_id
94
+
95
+ ip_permission.ip_ranges.each do |ip_range|
96
+ from = ip_range.cidr_ip.to_id
97
+
98
+ node from,
99
+ shape: "ellipse",
100
+ style: "filled",
101
+ color: "#E7FAFF",
102
+ fillcolor: "#E7FAFF",
103
+ label: ip_range.cidr_ip,
104
+ fontsize: options.fontsize,
105
+ fontname: options.fontname,
106
+ fontcolor: "#003E2F"
107
+
108
+ add_route :inbound, from, to, ip_permission
109
+ end
110
+
111
+ ip_permission.user_id_group_pairs.each do |user_id_group_pair|
112
+ from = if user_id_group_pair.user_id == security_group.owner_id
113
+ user_id_group_pair.group_id.to_id
114
+ else
115
+ node xaccount_sg(user_id_group_pair).to_id, xaccount_sg(user_id_group_pair)
116
+ xaccount_sg(user_id_group_pair).to_id
117
+ end
118
+
119
+ add_route :inbound, from, to, ip_permission
120
+ end
121
+ end
122
+
123
+ unless options.inbound_only
124
+ security_group.ip_permissions_egress.each do |ip_permission|
125
+ from = security_group.id.to_id
126
+
127
+ ip_permission.ip_ranges.each do |ip_range|
128
+ to = ip_range.cidr_ip.to_id
129
+
130
+ node to,
131
+ shape: "ellipse",
132
+ style: "filled",
133
+ color: "#E7FAFF",
134
+ fillcolor: "#E7FAFF",
135
+ label: ip_range.cidr_ip,
136
+ fontsize: options.fontsize,
137
+ fontname: options.fontname,
138
+ fontcolor: "#003E2F"
139
+
140
+ add_route :outbound, from, to, ip_permission
141
+ end
142
+
143
+ ip_permission.user_id_group_pairs.each do |user_id_group_pair|
144
+ to = if user_id_group_pair.user_id == security_group.owner_id
145
+ user_id_group_pair.group_id.to_id
146
+ else
147
+ node xaccount_sg(user_id_group_pair).to_id, xaccount_sg(user_id_group_pair)
148
+ xaccount_sg(user_id_group_pair).to_id
149
+ end
150
+
151
+ add_route :outbound, from, to, ip_permission
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ node "0.0.0.0/0".to_id,
159
+ label: "",
160
+ image: "#{__dir__}/images/internet.png",
161
+ peripheries: 0,
162
+ fixedsize: true,
163
+ imagescale: true,
164
+ shape: "circle",
165
+ width: 1.67
166
+
167
+ save options.output_path, options.format
168
+ end
169
+
170
+ private
171
+
172
+ def options
173
+ @options
174
+ end
175
+
176
+ def aws_configuration
177
+ hash = {}
178
+
179
+ [:profile, :access_key_id, :secret_access_key, :region].each do |option|
180
+ hash.update(option => options[option]) if options[option]
181
+ end
182
+
183
+ hash.update(region: own_region) if hash[:region].nil?
184
+ hash
185
+ end
186
+
187
+ def own_region
188
+ @own_region ||= begin
189
+ require "net/http"
190
+
191
+ timeout 3 do
192
+ Net::HTTP.get("169.254.169.254", "/latest/meta-data/placement/availability-zone").chop
193
+ end
194
+ rescue
195
+ nil
196
+ end
197
+ end
198
+
199
+ def ec2
200
+ @ec2 ||= Aws::EC2::Resource.new aws_configuration
201
+ end
202
+
203
+ # returns Hash like `{"vpc-1111111" => [sg1, sg2, ...], "vpc-11111112" => [sg3, sg4, ...], ...}`
204
+ def vpc_security_groups
205
+ ec2.security_groups.group_by(&:vpc_id).select do |vpc_id|
206
+ if options.vpc_ids
207
+ options.vpc_ids.include? vpc_id
208
+ else
209
+ true
210
+ end
211
+ end
212
+ end
213
+
214
+ def xaccount_sg user_id_group_pair
215
+ "#{user_id_group_pair.user_id}/#{user_id_group_pair.group_id}"
216
+ end
217
+
218
+ def add_route in_or_out = :inbound, from, to, ip_permission
219
+ id = :"#{from}_#{to}"
220
+ color = (in_or_out == :inbound ? "#003E2F" : "#045280")
221
+
222
+ traffic_map[id] = if traffic_map[id]
223
+ [traffic_map[id], route_label(ip_permission)].join("\\n")
224
+ else
225
+ route_label(ip_permission)
226
+ end
227
+
228
+ edge id,
229
+ label: traffic_map[id],
230
+ style: "bold",
231
+ arrowhead: (in_or_out == :inbound ? "normal" : "onormal"),
232
+ color: color,
233
+ fontname: options.fontname,
234
+ fontsize: (options.fontsize * 0.75),
235
+ fontcolor: color
236
+ end
237
+
238
+ def traffic_map
239
+ @traffic_map ||= {}
240
+ end
241
+
242
+ def route_label ip_permission
243
+ if ip_permission.ip_protocol == "-1"
244
+ "All Traffic"
245
+ elsif ip_permission.from_port == ip_permission.to_port
246
+ "#{ip_permission.ip_protocol.upcase}:#{ip_permission.to_port}"
247
+ else
248
+ "#{ip_permission.ip_protocol.upcase}:#{ip_permission.from_port}-#{ip_permission.to_port}"
249
+ end
250
+ end
251
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ module Sgviz
2
+ VERSION = "0.0.1"
3
+ end
data/lib/sgviz.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "sgviz/version"
2
+ require "sgviz/generator"
3
+ require "sgviz/cli"
data/sgviz.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sgviz/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sgviz"
8
+ spec.version = Sgviz::VERSION
9
+ spec.authors = ["y13i"]
10
+ spec.email = ["email@y13i.com"]
11
+ spec.summary = %(Visualize VPC Security Groups.)
12
+ spec.description = %(A visualization tool for AWS VPC Security Groups.)
13
+ spec.homepage = "https://github.com/y13i/sgviz"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "gviz"
25
+ spec.add_dependency "thor"
26
+ spec.add_dependency "aws-sdk-resources"
27
+ spec.add_dependency "aws-sdk-core"
28
+
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "awesome_print"
31
+ spec.add_development_dependency "kumogata"
32
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sgviz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - y13i
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: gviz
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: thor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aws-sdk-resources
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: aws-sdk-core
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: awesome_print
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: kumogata
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: A visualization tool for AWS VPC Security Groups.
140
+ email:
141
+ - email@y13i.com
142
+ executables:
143
+ - sgviz
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".gitignore"
148
+ - Gemfile
149
+ - LICENSE.txt
150
+ - README.md
151
+ - Rakefile
152
+ - bin/sgviz
153
+ - docs/cfn/example.json
154
+ - docs/cfn/example.rb
155
+ - docs/images/1.png
156
+ - lib/sgviz.rb
157
+ - lib/sgviz/cli.rb
158
+ - lib/sgviz/generator.rb
159
+ - lib/sgviz/images/aws.png
160
+ - lib/sgviz/images/internet.png
161
+ - lib/sgviz/images/vpc.png
162
+ - lib/sgviz/version.rb
163
+ - sgviz.gemspec
164
+ homepage: https://github.com/y13i/sgviz
165
+ licenses:
166
+ - MIT
167
+ metadata: {}
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 2.4.5
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Visualize VPC Security Groups.
188
+ test_files: []