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

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 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