aws_security_viz 0.1.7.pre.alpha.pre.145 → 0.2.0.pre.alpha.pre.152

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81e70d70b82e3e9113db28bfb55d061f7e6c994169873fbc110ae681f63d581b
4
- data.tar.gz: 7d8975aeb070a34b7ca6a4e3ee93039eb90404183927bcbec497b4a02c6d22ff
3
+ metadata.gz: be9db3036820a8e139ef5efdce90c341df24e582dbd8aa7ef7db4b5cfe569926
4
+ data.tar.gz: 3c64a76b19594f12c42c90afac0fb4577c8be33cf7e1c66bcdf2a85eef7aee24
5
5
  SHA512:
6
- metadata.gz: 1a535538adadb009119a333e4e0cfbcc88d40db76db39f051839b4b03da57edfd8e14398ff1968f8760086f7aac32a256266ef3a8320c98b3a7adb7913226e34
7
- data.tar.gz: 29b361a049411f6b51b2877a3ee9f9a1ba2d81a0002fb6d43882dbec94041c8911b46217d2f7584a7dcfabe668b01973d66be5e7c7752a0820ffdd3ca6e3d374
6
+ metadata.gz: 378d4705ee99b1b4a8cef8384205d99ccbf8865d3926a83a009c0eb343e9940c88acac971fd8321a93aea622ca3e20832b3a19d87c18d7d5711ab2462c0b7d86
7
+ data.tar.gz: bf04ed0f86ecef83e8286d97138fca3e485d1d7eeb0333344ecb5ff819b109497b8af687529c6b04122b87d22380afea3e21a052f1df4ba2705a8e31905b3810
@@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
+ ### Added
7
+ - Add graph navigator renderer using https://grapheco.github.io/InteractiveGraph/
8
+
9
+ ### Changed
10
+ - Renderer no longer identified automatically based on json file extension.
6
11
 
7
12
  ## [0.1.6] - 2019-01-14
8
13
  ### Added
data/README.md CHANGED
@@ -42,7 +42,7 @@ To generate the graph using an existing security_groups.json (created using aws-
42
42
  To generate a web view
43
43
 
44
44
  ```
45
- $ aws_security_viz -a your_aws_key -s your_aws_secret_key -f aws.json
45
+ $ aws_security_viz -a your_aws_key -s your_aws_secret_key -f aws.json --renderer navigator
46
46
  ```
47
47
 
48
48
  * Generates two files: aws.json and view.html.
@@ -13,6 +13,7 @@ opts = Optimist::options do
13
13
  opt :filename, 'Output file name', :type => :string, :default => 'aws-security-viz.png'
14
14
  opt :config, 'Config file (opts.yml)', :type => :string, :default => 'opts.yml'
15
15
  opt :color, 'Colored node edges', :default => false
16
+ opt :renderer, "Renderer (#{Renderer.all.join('|')})", :default => 'graphviz'
16
17
  opt :source_filter, 'Source filter', :default => nil, :type => :string
17
18
  opt :target_filter, 'Target filter', :default => nil, :type => :string
18
19
  end
@@ -29,5 +30,6 @@ begin
29
30
  VisualizeAws.new(config, opts).unleash(opts[:filename])
30
31
  rescue Exception => e
31
32
  puts "[ERROR] #{e.message}"
33
+ raise e if config.debug?
32
34
  exit 1
33
35
  end
@@ -1,3 +1,5 @@
1
+ require 'yaml'
2
+
1
3
  class AwsConfig
2
4
  def initialize(opts={})
3
5
  @opts = opts
@@ -1,8 +1,7 @@
1
1
  require_relative 'ec2/security_groups'
2
2
  require_relative 'provider/json'
3
3
  require_relative 'provider/ec2'
4
- require_relative 'renderer/graphviz'
5
- require_relative 'renderer/json'
4
+ require_relative 'renderer/all'
6
5
  require_relative 'graph'
7
6
  require_relative 'graph_filter'
8
7
  require_relative 'exclusions'
@@ -21,20 +20,14 @@ class VisualizeAws
21
20
  def unleash(output_file)
22
21
  g = build
23
22
  g.filter(@options[:source_filter], @options[:target_filter])
24
- if output_file.end_with?('json')
25
- g.output(Renderer::Json.new(output_file, @config))
26
- FileUtils.copy(File.expand_path('../export/html/view.html', __FILE__),
27
- File.expand_path('../view.html', output_file))
28
- else
29
- g.output(Renderer::GraphViz.new(output_file, @config))
30
- end
23
+ g.output(Renderer.pick(@options[:renderer], output_file, @config))
31
24
  end
32
25
 
33
26
  def build
34
27
  g = @config.obfuscate? ? DebugGraph.new(@config) : Graph.new(@config)
35
28
  @security_groups.each_with_index { |group, index|
36
29
  picker = ColorPicker.new(@options[:color])
37
- g.add_node(group.name)
30
+ g.add_node(group.name, {vpc_id: group.vpc_id, group_id: group.group_id})
38
31
  group.traffic.each { |traffic|
39
32
  if traffic.ingress
40
33
  g.add_edge(traffic.from, traffic.to, :color => picker.color(index, traffic.ingress), :label => traffic.port_range)
@@ -13,7 +13,7 @@ def debug
13
13
  File.readlines('debug-output.log').map do |l|
14
14
  type, left, right = l.split(/\W+/)
15
15
  if type=="node"
16
- g.add_node(h(left))
16
+ g.add_node(h(left), {})
17
17
  elsif type=="edge"
18
18
  g.add_edge(h(left), h(right), {})
19
19
  end
@@ -6,8 +6,8 @@ class DebugGraph
6
6
  @g = Graph.new(config)
7
7
  end
8
8
 
9
- def add_node(name)
10
- @g.add_node(h(name)) if name
9
+ def add_node(name, opts)
10
+ @g.add_node(h(name), opts) if name
11
11
  end
12
12
 
13
13
  def add_edge(from, to, opts)
@@ -29,7 +29,7 @@ end
29
29
  class SecurityGroup
30
30
  extend Forwardable
31
31
 
32
- def_delegator :@group, :name
32
+ def_delegators :@group, :name, :vpc_id, :group_id
33
33
 
34
34
  def initialize(all_groups, group, config)
35
35
  @all_groups = all_groups
@@ -0,0 +1,84 @@
1
+ <html>
2
+
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <title>GraphNavigator</title>
6
+ <script type="text/javascript" src="https://rawcdn.githack.com/grapheco/InteractiveGraph/0.1.1/dist/igraph/interactive-graph.min.js"></script>
7
+ <link type="text/css" rel="stylesheet" href="https://rawcdn.githack.com/grapheco/InteractiveGraph/0.1.1/dist/igraph/interactive-graph.min.css">
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
9
+ crossorigin="anonymous"></script>
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" integrity="sha256-p6xU9YulB7E2Ic62/PX+h59ayb3PBJ0WFTEQxq0EjHw="
11
+ crossorigin="anonymous" />
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha256-KM512VNnjElC30ehFwehXjx1YCHPiQkOPmqnrWtpccM="
13
+ crossorigin="anonymous"></script>
14
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
15
+ integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
16
+ <style type="text/css">
17
+ body {
18
+ margin: 0px;
19
+ font-size: 14px;
20
+ }
21
+
22
+ #graphArea {
23
+ height: 100%;
24
+ border: 1px solid lightgray;
25
+ }
26
+ div.vis-configuration.vis-config-item.vis-config-s3, div.vis-configuration.vis-config-item.vis-config-s2,div.vis-configuration.vis-config-item.vis-config-s0 {
27
+ background-color: #f7f8fa
28
+ }
29
+ .configure {
30
+ padding: 4px;
31
+ position: absolute;
32
+ bottom: 10px;
33
+ right: 10px;
34
+ background: #f7f8fa;
35
+ width: 520px;
36
+ box-shadow: rgba(116, 112, 112, .555) 1px 1px 10px;
37
+ z-index: 900
38
+ }
39
+ </style>
40
+
41
+ </head>
42
+
43
+ <body>
44
+ <div style="height:100%">
45
+ <div id="graphArea"></div>
46
+ <div class="configure">
47
+ <span class="fa fa-cogs"></span>
48
+ <a href="#" class="toggle-config">Configure</a>
49
+ <div id="configOptions" style="display:none"></div>
50
+ </div>
51
+ </div>
52
+
53
+ <script type="text/javascript">
54
+ $('.toggle-config').click(function () {
55
+ $('#configOptions').slideToggle('slow');
56
+ });
57
+ function trackAndNavigate(e) {
58
+ e.nodes.forEach(element => {
59
+ var deleted = window.nodes.delete(element)
60
+ if (!deleted) {
61
+ window.nodes.add(element);
62
+ }
63
+ });
64
+ if (window.nodes.size >= 2) {
65
+ var [from, to] = window.nodes;
66
+ window.location.search = `from=${from}&to=${to}`;
67
+ }
68
+ }
69
+ var file = location.hash.replace(/^#/, '/');
70
+ var app = new igraph.GraphNavigator(document.getElementById('graphArea'));
71
+ app.loadGson(file);
72
+ app._frame._networkOptions.configure = {
73
+ filter: (option, path) => path.indexOf('physics') !== -1,
74
+ container: document.getElementById('configOptions'),
75
+ showButton: false
76
+ }
77
+ app._frame.updateNetworkOptions(app._frame._networkOptions)
78
+
79
+ window.nodes = new Set();
80
+ app._frame.on('NETWORK_DBLCLICK', trackAndNavigate);
81
+ </script>
82
+ </body>
83
+
84
+ </html>
@@ -7,11 +7,13 @@ class Graph
7
7
  @config = config
8
8
  @underlying = underlying
9
9
  @edge_properties = {}
10
+ @node_properties = {}
10
11
  end
11
12
 
12
- def add_node(name)
13
- log("node: #{name}")
13
+ def add_node(name, opts)
14
+ log("node: #{name}, opts: #{opts}")
14
15
  @underlying.add_vertex(name)
16
+ @node_properties[name] = opts
15
17
  end
16
18
 
17
19
  def add_edge(from, to, opts)
@@ -25,7 +27,7 @@ class Graph
25
27
  end
26
28
 
27
29
  def output(renderer)
28
- @underlying.each_vertex { |v| renderer.add_node(v) }
30
+ @underlying.each_vertex { |v| renderer.add_node(v, @node_properties[v] || {}) }
29
31
  @underlying.each_edge { |u, v|
30
32
  renderer.add_edge(u, v, opts(u, v))
31
33
  }
@@ -26,7 +26,7 @@ end
26
26
  module Ec2
27
27
  class SecurityGroup
28
28
  extend Forwardable
29
- def_delegators :@sg, :name, :group_id
29
+ def_delegators :@sg, :name, :group_id, :vpc_id
30
30
  def initialize(sg)
31
31
  @sg = sg
32
32
  end
@@ -22,6 +22,14 @@ module Json
22
22
  @sg['GroupName']
23
23
  end
24
24
 
25
+ def group_id
26
+ @sg['GroupId']
27
+ end
28
+
29
+ def vpc_id
30
+ @sg['VpcId']
31
+ end
32
+
25
33
  def ip_permissions
26
34
  @sg['IpPermissions'].collect { |ip|
27
35
  Json::IpPermission.new(ip)
@@ -0,0 +1,18 @@
1
+ require_relative 'navigator'
2
+ require_relative 'json'
3
+ require_relative 'graphviz'
4
+ module Renderer
5
+ ALL = {graphviz: Renderer::GraphViz, json: Renderer::Json, navigator: Renderer::Navigator}
6
+ def self.pick(r, output_file, config)
7
+ (ALL[(r || 'graphviz').to_sym]).new(output_file, config)
8
+ end
9
+
10
+ def self.copy_asset(asset, file_name)
11
+ FileUtils.copy(File.expand_path("../../export/html/#{asset}", __FILE__),
12
+ File.expand_path(asset, @file_name))
13
+ end
14
+
15
+ def self.all
16
+ ALL.keys
17
+ end
18
+ end
@@ -14,7 +14,7 @@ module Renderer
14
14
  @config = config
15
15
  end
16
16
 
17
- def add_node(name)
17
+ def add_node(name, opts)
18
18
  @g.add_node(name, label: name)
19
19
  end
20
20
 
@@ -27,7 +27,7 @@ module Renderer
27
27
 
28
28
  def create_if_missing(name)
29
29
  n = @g.get_node(name).first
30
- n.nil? ? add_node(name) : n
30
+ n.nil? ? add_node(name, {}) : n
31
31
  end
32
32
 
33
33
  def output
@@ -7,7 +7,7 @@ module Renderer
7
7
  @config = config
8
8
  end
9
9
 
10
- def add_node(name)
10
+ def add_node(name, opts)
11
11
  @nodes << {id: name, label: name}
12
12
  end
13
13
 
@@ -17,7 +17,7 @@ module Renderer
17
17
 
18
18
  def output
19
19
  IO.write(@file_name, {nodes: @nodes, edges: @edges}.to_json)
20
+ Renderer.copy_asset('view.html', @file_name)
20
21
  end
21
-
22
22
  end
23
23
  end
@@ -0,0 +1,32 @@
1
+ require 'set'
2
+
3
+ module Renderer
4
+ class Navigator
5
+ def initialize(file_name, config)
6
+ @nodes = []
7
+ @edges = []
8
+ @file_name = file_name
9
+ @config = config
10
+ @categories = Set.new()
11
+ end
12
+
13
+ def add_node(name, opts)
14
+ vpc = opts[:vpc_id] || 'default'
15
+ @nodes << {id: name, label: name, categories: [vpc]}
16
+ @categories.add(vpc)
17
+ end
18
+
19
+ def add_edge(from, to, opts)
20
+ @edges << {id: "#{from}-#{to}", from: from, to: to, label: opts[:label]}
21
+ end
22
+
23
+ def output
24
+ IO.write(@file_name, {
25
+ data: {nodes: @nodes, edges: @edges},
26
+ categories: Hash[@categories.map{|c| [c, c]}]
27
+ }.to_json)
28
+ Renderer.copy_asset('navigator.html', @file_name)
29
+ end
30
+ end
31
+ end
32
+
@@ -1,3 +1,3 @@
1
1
  module AwsSecurityViz
2
- VERSION = '0.1.7'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1 @@
1
+ {"categories": {"default":"default"}, "data": {"nodes":[{"id":"app", "label":"app", "categories":["default"]}, {"id":"8.8.8.8/32", "label":"8.8.8.8/32", "categories":["default"]}, {"id":"amazon-elb-sg", "label":"amazon-elb-sg", "categories":["default"]}, {"id":"*", "label":"*", "categories":["default"]}, {"id":"db", "label":"db", "categories":["default"]}], "edges":[{"id":"app-db", "from":"app", "to":"db", "label":"5984/tcp"}, {"id":"8.8.8.8/32-app", "from":"8.8.8.8/32", "to":"app", "label":"80/tcp"}, {"id":"amazon-elb-sg-app", "from":"amazon-elb-sg", "to":"app", "label":"80/tcp"}, {"id":"*-app", "from":"*", "to":"app", "label":"22/tcp"}]}}
@@ -29,7 +29,18 @@ describe VisualizeAws do
29
29
 
30
30
  it 'should parse json input', :integration => true do
31
31
  expect(FileUtils).to receive(:copy)
32
- VisualizeAws.new(config, opts).unleash(temp_file.path)
32
+ VisualizeAws.new(config, opts.merge(:renderer => 'json')).unleash(temp_file.path)
33
+ expect(JSON.parse(expected_content)).to eq(JSON.parse(actual_content))
34
+ end
35
+ end
36
+
37
+ context 'json to navigator file' do
38
+ let(:expected_file) { File.join(File.dirname(__FILE__), 'navigator.json') }
39
+ let(:temp_file) { Tempfile.new(%w(aws .json)) }
40
+
41
+ it 'should parse json input', :integration => true do
42
+ expect(FileUtils).to receive(:copy)
43
+ VisualizeAws.new(config, opts.merge(:renderer => 'navigator')).unleash(temp_file.path)
33
44
  expect(JSON.parse(expected_content)).to eq(JSON.parse(actual_content))
34
45
  end
35
46
  end
@@ -7,7 +7,7 @@ class DummyRenderer
7
7
  @output = []
8
8
  end
9
9
 
10
- def add_node(name)
10
+ def add_node(name, opts)
11
11
  @output << [:node, name]
12
12
  end
13
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_security_viz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7.pre.alpha.pre.145
4
+ version: 0.2.0.pre.alpha.pre.152
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anay Nayak
@@ -191,14 +191,17 @@ files:
191
191
  - lib/ec2/security_groups.rb
192
192
  - lib/ec2/traffic.rb
193
193
  - lib/exclusions.rb
194
+ - lib/export/html/navigator.html
194
195
  - lib/export/html/view.html
195
196
  - lib/graph.rb
196
197
  - lib/graph_filter.rb
197
198
  - lib/opts.yml.sample
198
199
  - lib/provider/ec2.rb
199
200
  - lib/provider/json.rb
201
+ - lib/renderer/all.rb
200
202
  - lib/renderer/graphviz.rb
201
203
  - lib/renderer/json.rb
204
+ - lib/renderer/navigator.rb
202
205
  - lib/version.rb
203
206
  - spec/color_picker_spec.rb
204
207
  - spec/graph_filter_spec.rb
@@ -206,6 +209,7 @@ files:
206
209
  - spec/integration/dummy.dot
207
210
  - spec/integration/dummy.json
208
211
  - spec/integration/expected.json
212
+ - spec/integration/navigator.json
209
213
  - spec/integration/visualize_aws_spec.rb
210
214
  - spec/spec_helper.rb
211
215
  - spec/visualize_aws_spec.rb
@@ -239,6 +243,7 @@ test_files:
239
243
  - spec/integration/dummy.dot
240
244
  - spec/integration/dummy.json
241
245
  - spec/integration/expected.json
246
+ - spec/integration/navigator.json
242
247
  - spec/integration/visualize_aws_spec.rb
243
248
  - spec/spec_helper.rb
244
249
  - spec/visualize_aws_spec.rb