aws_security_viz 0.2.5.pre.alpha.pre.35 → 1.0.0
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 +4 -4
- data/CHANGELOG.md +59 -1
- data/README.md +120 -79
- data/exe/aws_security_viz +4 -40
- data/lib/aws_security_viz/aws_config.rb +80 -0
- data/lib/aws_security_viz/cli.rb +151 -0
- data/lib/aws_security_viz/cli_guard.rb +39 -0
- data/lib/aws_security_viz/directed_graph.rb +72 -0
- data/lib/aws_security_viz/ec2/security_groups.rb +74 -0
- data/lib/aws_security_viz/exclusions.rb +18 -0
- data/lib/aws_security_viz/export/html/viewer.html +222 -0
- data/lib/aws_security_viz/graph.rb +93 -0
- data/lib/aws_security_viz/graph_filter.rb +20 -0
- data/lib/aws_security_viz/logging.rb +18 -0
- data/lib/aws_security_viz/model.rb +87 -0
- data/lib/aws_security_viz/obfuscation.rb +45 -0
- data/lib/{opts.yml.sample → aws_security_viz/opts.yml.sample} +2 -0
- data/lib/aws_security_viz/port_label.rb +44 -0
- data/lib/aws_security_viz/provider/ec2.rb +84 -0
- data/lib/aws_security_viz/provider/json.rb +17 -0
- data/lib/aws_security_viz/renderer/all.rb +49 -0
- data/lib/aws_security_viz/renderer/graphviz.rb +119 -0
- data/lib/aws_security_viz/renderer/html.rb +46 -0
- data/lib/aws_security_viz/renderer/json.rb +29 -0
- data/lib/aws_security_viz/renderer/mermaid.rb +105 -0
- data/lib/aws_security_viz/risk.rb +18 -0
- data/lib/aws_security_viz/vendor/cytoscape/LICENSE +19 -0
- data/lib/aws_security_viz/vendor/cytoscape/README.md +15 -0
- data/lib/aws_security_viz/vendor/cytoscape/cytoscape.min.js +31 -0
- data/lib/aws_security_viz/version.rb +5 -0
- data/lib/aws_security_viz.rb +44 -37
- metadata +39 -232
- data/.dockerignore +0 -7
- data/.editorconfig +0 -17
- data/.github/dependabot.yml +0 -15
- data/.github/workflows/ruby.yml +0 -34
- data/.github/workflows/rubygem.yml +0 -29
- data/.github/workflows/rubygem_release.yml +0 -27
- data/.gitignore +0 -43
- data/.tool-versions +0 -1
- data/CODE_OF_CONDUCT.md +0 -46
- data/Dockerfile +0 -9
- data/Gemfile +0 -3
- data/Rakefile +0 -15
- data/Vagrantfile +0 -18
- data/aws_security_viz.gemspec +0 -40
- data/config/boot.rb +0 -4
- data/images/sample.png +0 -0
- data/lib/aws_config.rb +0 -44
- data/lib/color_picker.rb +0 -245
- data/lib/debug/parse_log.rb +0 -26
- data/lib/debug_graph.rb +0 -29
- data/lib/ec2/ip_permission.rb +0 -35
- data/lib/ec2/security_groups.rb +0 -78
- data/lib/ec2/traffic.rb +0 -32
- data/lib/exclusions.rb +0 -14
- data/lib/export/html/navigator.html +0 -84
- data/lib/export/html/view.html +0 -163
- data/lib/graph.rb +0 -45
- data/lib/graph_filter.rb +0 -38
- data/lib/provider/ec2.rb +0 -105
- data/lib/provider/json.rb +0 -104
- data/lib/renderer/all.rb +0 -18
- data/lib/renderer/graphviz.rb +0 -37
- data/lib/renderer/json.rb +0 -23
- data/lib/renderer/navigator.rb +0 -33
- data/lib/version.rb +0 -3
- data/spec/color_picker_spec.rb +0 -20
- data/spec/graph_filter_spec.rb +0 -85
- data/spec/integration/aws_expected.json +0 -1
- data/spec/integration/dummy.dot +0 -50
- data/spec/integration/dummy.json +0 -64
- data/spec/integration/expected.json +0 -1
- data/spec/integration/navigator.json +0 -1
- data/spec/integration/visualize_aws_spec.rb +0 -96
- data/spec/spec_helper.rb +0 -36
- data/spec/visualize_aws_spec.rb +0 -194
data/lib/export/html/view.html
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
<html>
|
|
2
|
-
<head>
|
|
3
|
-
<style type="text/css">
|
|
4
|
-
#container {
|
|
5
|
-
max-width: 100%;
|
|
6
|
-
height: 100%;
|
|
7
|
-
margin: auto;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
#error {
|
|
11
|
-
color: #31708f;
|
|
12
|
-
background-color: #d9edf7;
|
|
13
|
-
padding: 15px;
|
|
14
|
-
margin-bottom: 20px;
|
|
15
|
-
border: 1px solid transparent;
|
|
16
|
-
border-radius: 4px;
|
|
17
|
-
}
|
|
18
|
-
</style>
|
|
19
|
-
</head>
|
|
20
|
-
<body>
|
|
21
|
-
<div id="error" style="display:none"></div>
|
|
22
|
-
<div id="container"></div>
|
|
23
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/sigma.min.js"></script>
|
|
24
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/plugins/sigma.parsers.json.min.js"></script>
|
|
25
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/plugins/sigma.layouts.forceLink.min.js"></script>
|
|
26
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/plugins/sigma.plugins.design.min.js"></script>
|
|
27
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/plugins/sigma.plugins.colorbrewer.min.js"></script>
|
|
28
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/linkurious.js/1.5.0/plugins/sigma.renderers.edgeLabels.min.js"></script>
|
|
29
|
-
<script>
|
|
30
|
-
sigma.classes.graph.addMethod('neighbors', function (nodeId) {
|
|
31
|
-
var k,
|
|
32
|
-
neighbors = {},
|
|
33
|
-
index = this.allNeighborsIndex[nodeId] || {};
|
|
34
|
-
|
|
35
|
-
for (k in index)
|
|
36
|
-
neighbors[k] = this.nodesIndex[k];
|
|
37
|
-
|
|
38
|
-
return neighbors;
|
|
39
|
-
});
|
|
40
|
-
sigma.classes.graph.addMethod('neighborCount', function (nodeId) {
|
|
41
|
-
return this.allNeighborsCount[nodeId];
|
|
42
|
-
});
|
|
43
|
-
var config = {
|
|
44
|
-
renderer: {
|
|
45
|
-
container: 'container',
|
|
46
|
-
type: 'canvas'
|
|
47
|
-
},
|
|
48
|
-
settings: {
|
|
49
|
-
animationsTime: 1000,
|
|
50
|
-
borderSize: 1,
|
|
51
|
-
outerBorderSize: 1,
|
|
52
|
-
defaultNodeOuterBorderColor: 'rgb(236, 81, 72)',
|
|
53
|
-
enableEdgeHovering: true,
|
|
54
|
-
edgeHoverHighlightNodes: 'circle',
|
|
55
|
-
sideMargin: 1,
|
|
56
|
-
edgeHoverColor: 'edge',
|
|
57
|
-
defaultEdgeHoverColor: '#000',
|
|
58
|
-
edgeHoverExtremities: true,
|
|
59
|
-
scalingMode: 'outside',
|
|
60
|
-
edgeLabelThreshold: 2,
|
|
61
|
-
edgeHoverSizeRatio: 2,
|
|
62
|
-
edgeLabelSize: 'proportional'
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
var graphUrl = function () {
|
|
66
|
-
return window.location.hash.replace(/^#/, '/');
|
|
67
|
-
};
|
|
68
|
-
var errorElement = document.getElementById("error");
|
|
69
|
-
window.onhashchange = function () {
|
|
70
|
-
loadGraph(graphUrl());
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
function loadGraph(url) {
|
|
74
|
-
errorElement.style.display = "none";
|
|
75
|
-
var initializeGraph = function (s) {
|
|
76
|
-
s.graph.nodes().forEach(function (n) {
|
|
77
|
-
n.x = Math.random();
|
|
78
|
-
n.y = Math.random();
|
|
79
|
-
n.size = 1;
|
|
80
|
-
n.label = n.id;
|
|
81
|
-
n.data = {edgeCount: s.graph.neighborCount(n.id)};
|
|
82
|
-
});
|
|
83
|
-
var myStyles = {
|
|
84
|
-
nodes: {
|
|
85
|
-
color: {
|
|
86
|
-
by: 'data.edgeCount',
|
|
87
|
-
scheme: 'colorbrewer.nodes',
|
|
88
|
-
bins: 3
|
|
89
|
-
},
|
|
90
|
-
size: {
|
|
91
|
-
by: 'data.edgeCount',
|
|
92
|
-
bins: 7,
|
|
93
|
-
min: 2,
|
|
94
|
-
max: 10
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
var myPalette = {
|
|
99
|
-
colorbrewer: {
|
|
100
|
-
nodes: sigma.plugins.colorbrewer.Dark2
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
var design = sigma.plugins.design(s, {styles: myStyles, palette: myPalette});
|
|
104
|
-
design.apply();
|
|
105
|
-
|
|
106
|
-
s.graph.nodes().forEach(function (n) {
|
|
107
|
-
n.originalColor = n.color;
|
|
108
|
-
});
|
|
109
|
-
s.graph.edges().forEach(function (e) {
|
|
110
|
-
e.size = 1;
|
|
111
|
-
e.originalColor = e.color;
|
|
112
|
-
e.type = "arrow";
|
|
113
|
-
});
|
|
114
|
-
var fa = sigma.layouts.startForceLink(s, {autoStop: true, adjustSizes: true, randomize: true});
|
|
115
|
-
|
|
116
|
-
s.bind('clickNode', function (e) {
|
|
117
|
-
var nodeId = e.data.node.id,
|
|
118
|
-
toKeep = s.graph.neighbors(nodeId);
|
|
119
|
-
toKeep[nodeId] = e.data.node;
|
|
120
|
-
|
|
121
|
-
s.graph.nodes().forEach(function (n) {
|
|
122
|
-
if (toKeep[n.id])
|
|
123
|
-
n.color = n.originalColor;
|
|
124
|
-
else
|
|
125
|
-
n.color = '#eee';
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
s.graph.edges().forEach(function (e) {
|
|
129
|
-
if (toKeep[e.source] && toKeep[e.target])
|
|
130
|
-
e.color = e.originalColor;
|
|
131
|
-
else
|
|
132
|
-
e.color = '#eee';
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
s.refresh();
|
|
136
|
-
});
|
|
137
|
-
s.bind('clickStage', function (e) {
|
|
138
|
-
s.graph.nodes().forEach(function (n) {
|
|
139
|
-
n.color = n.originalColor;
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
s.graph.edges().forEach(function (e) {
|
|
143
|
-
e.color = e.originalColor;
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
s.refresh();
|
|
147
|
-
});
|
|
148
|
-
};
|
|
149
|
-
sigma.parsers.json(url, config, initializeGraph);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
var url = graphUrl();
|
|
153
|
-
if (url) {
|
|
154
|
-
loadGraph(graphUrl());
|
|
155
|
-
} else {
|
|
156
|
-
var link = '<a href="' + location.href + '#test.json">' + location.href + '#test.json</a>';
|
|
157
|
-
errorElement.innerHTML = "Please pass in a datasource via html fragment identifier. For e.g. " + link;
|
|
158
|
-
errorElement.style.display = "";
|
|
159
|
-
}
|
|
160
|
-
</script>
|
|
161
|
-
</body>
|
|
162
|
-
</html>
|
|
163
|
-
|
data/lib/graph.rb
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require 'rgl/adjacency'
|
|
2
|
-
|
|
3
|
-
class Graph
|
|
4
|
-
attr_reader :underlying
|
|
5
|
-
|
|
6
|
-
def initialize(config, underlying=RGL::DirectedAdjacencyGraph.new)
|
|
7
|
-
@config = config
|
|
8
|
-
@underlying = underlying
|
|
9
|
-
@edge_properties = {}
|
|
10
|
-
@node_properties = {}
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def add_node(name, opts)
|
|
14
|
-
log("node: #{name}, opts: #{opts}")
|
|
15
|
-
@underlying.add_vertex(name)
|
|
16
|
-
@node_properties[name] = opts
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def add_edge(from, to, opts)
|
|
20
|
-
log("edge: #{from} -> #{to}")
|
|
21
|
-
@underlying.add_edge(from, to)
|
|
22
|
-
@edge_properties[[from, to]] = opts
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def filter(source, destination)
|
|
26
|
-
@underlying = GraphFilter.new(underlying).filter(source, destination)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def output(renderer)
|
|
30
|
-
@underlying.each_vertex { |v| renderer.add_node(v, @node_properties[v] || {}) }
|
|
31
|
-
@underlying.each_edge { |u, v|
|
|
32
|
-
renderer.add_edge(u, v, opts(u, v))
|
|
33
|
-
}
|
|
34
|
-
renderer.output
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def log(msg)
|
|
38
|
-
puts msg if @config.debug?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
def opts(u, v)
|
|
43
|
-
@edge_properties[[u, v]]
|
|
44
|
-
end
|
|
45
|
-
end
|
data/lib/graph_filter.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
require 'rgl/traversal'
|
|
2
|
-
require 'rgl/implicit'
|
|
3
|
-
|
|
4
|
-
class GraphFilter
|
|
5
|
-
def initialize(graph)
|
|
6
|
-
@graph = graph
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def filter(source, destination)
|
|
10
|
-
return @graph if source.nil? && destination.nil?
|
|
11
|
-
if !source.nil? && destination.nil?
|
|
12
|
-
return reduce(@graph, source)
|
|
13
|
-
end
|
|
14
|
-
if !destination.nil? && source.nil?
|
|
15
|
-
return reduce(@graph.reverse, destination).reverse
|
|
16
|
-
end
|
|
17
|
-
search(@graph, source, destination)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
def reduce(graph, source)
|
|
22
|
-
tree = graph.bfs_search_tree_from(source)
|
|
23
|
-
graph.vertices_filtered_by { |v| tree.has_vertex? v }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def search(graph, source, destination)
|
|
27
|
-
visitor = RGL::DFSVisitor.new(graph)
|
|
28
|
-
path = []
|
|
29
|
-
paths = []
|
|
30
|
-
visitor.set_examine_vertex_event_handler { |x| path << x }
|
|
31
|
-
visitor.set_finish_vertex_event_handler { |x| path.pop }
|
|
32
|
-
visitor.set_examine_edge_event_handler { |x, y| paths << path.clone + [y] if y == destination }
|
|
33
|
-
graph.depth_first_visit(source, visitor) { |x|}
|
|
34
|
-
to_remove = graph.vertices - paths.flatten
|
|
35
|
-
graph.remove_vertices(*to_remove)
|
|
36
|
-
graph
|
|
37
|
-
end
|
|
38
|
-
end
|
data/lib/provider/ec2.rb
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
require 'aws-sdk-ec2'
|
|
2
|
-
|
|
3
|
-
class Ec2Provider
|
|
4
|
-
|
|
5
|
-
def initialize(options)
|
|
6
|
-
@options = options
|
|
7
|
-
conn_opts = {
|
|
8
|
-
region: options[:region],
|
|
9
|
-
access_key_id: options[:access_key],
|
|
10
|
-
secret_access_key: options[:secret_key],
|
|
11
|
-
session_token: options[:session_token]
|
|
12
|
-
}.delete_if {|k,v| v.nil?}
|
|
13
|
-
|
|
14
|
-
@client = Aws::EC2::Client.new(conn_opts)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def security_groups
|
|
18
|
-
@client.describe_security_groups.security_groups.reject { |sg|
|
|
19
|
-
@options[:vpc_id] && sg.vpc_id != @options[:vpc_id]
|
|
20
|
-
}.collect { |sg|
|
|
21
|
-
Ec2::SecurityGroup.new(sg)
|
|
22
|
-
}
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
module Ec2
|
|
27
|
-
class SecurityGroup
|
|
28
|
-
extend Forwardable
|
|
29
|
-
def_delegators :@sg, :name, :group_id, :vpc_id
|
|
30
|
-
def initialize(sg)
|
|
31
|
-
@sg = sg
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def name
|
|
35
|
-
@sg.group_name
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def ip_permissions
|
|
39
|
-
@sg.ip_permissions.collect { |ip|
|
|
40
|
-
Ec2::IpPermission.new(ip)
|
|
41
|
-
}
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def ip_permissions_egress
|
|
45
|
-
@sg.ip_permissions_egress.collect { |ip|
|
|
46
|
-
Ec2::IpPermission.new(ip)
|
|
47
|
-
}
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
class IpPermission
|
|
52
|
-
def initialize(ip)
|
|
53
|
-
@ip = ip
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def protocol
|
|
57
|
-
@ip['ip_protocol']
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def from
|
|
61
|
-
@ip['from_port']
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def to
|
|
65
|
-
@ip['to_port']
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def ip_ranges
|
|
69
|
-
@ip['ip_ranges'].collect {|gp|
|
|
70
|
-
Ec2::IpPermissionRange.new(gp)
|
|
71
|
-
}
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def groups
|
|
75
|
-
@ip['user_id_group_pairs'].collect {|gp|
|
|
76
|
-
Ec2::IpPermissionGroup.new(gp)
|
|
77
|
-
}
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
class IpPermissionRange
|
|
82
|
-
def initialize(range)
|
|
83
|
-
@range = range
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def cidr_ip
|
|
87
|
-
@range['cidr_ip']
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def to_str
|
|
91
|
-
cidr_ip
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
class IpPermissionGroup
|
|
96
|
-
def initialize(gp)
|
|
97
|
-
@gp = gp
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def name
|
|
101
|
-
@gp['group_name'] || @gp['group_id']
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
end
|
data/lib/provider/json.rb
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
|
|
3
|
-
class JsonProvider
|
|
4
|
-
def initialize(options)
|
|
5
|
-
@groups = JSON.parse(File.read(options[:source_file]))['SecurityGroups']
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def security_groups
|
|
9
|
-
@groups.collect { |sg|
|
|
10
|
-
Json::SecurityGroup.new(sg)
|
|
11
|
-
}
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
module Json
|
|
16
|
-
class SecurityGroup
|
|
17
|
-
def initialize(sg)
|
|
18
|
-
@sg = sg
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def name
|
|
22
|
-
@sg['GroupName']
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def group_id
|
|
26
|
-
@sg['GroupId']
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def vpc_id
|
|
30
|
-
@sg['VpcId']
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def ip_permissions
|
|
34
|
-
@sg['IpPermissions'].collect { |ip|
|
|
35
|
-
Json::IpPermission.new(ip)
|
|
36
|
-
}
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def group_id
|
|
40
|
-
@sg['GroupId']
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def ip_permissions_egress
|
|
44
|
-
@sg['IpPermissionsEgress'].collect { |ip|
|
|
45
|
-
Json::IpPermission.new(ip)
|
|
46
|
-
}
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
class IpPermission
|
|
51
|
-
def initialize(ip)
|
|
52
|
-
@ip = ip
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def protocol
|
|
56
|
-
@ip['IpProtocol']
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def from
|
|
60
|
-
@ip['FromPort']
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def to
|
|
64
|
-
@ip['ToPort']
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def ip_ranges
|
|
68
|
-
@ip['IpRanges'].collect { |gp|
|
|
69
|
-
Json::IpPermissionRange.new(gp)
|
|
70
|
-
}
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def groups
|
|
74
|
-
@ip['UserIdGroupPairs'].collect { |pair|
|
|
75
|
-
Json::IpPermissionGroup.new(pair)
|
|
76
|
-
}
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
class IpPermissionRange
|
|
82
|
-
def initialize(range)
|
|
83
|
-
@range = range
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def cidr_ip
|
|
87
|
-
@range['CidrIp']
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def to_str
|
|
91
|
-
cidr_ip
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
class IpPermissionGroup
|
|
96
|
-
def initialize(gp)
|
|
97
|
-
@gp = gp
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def name
|
|
101
|
-
@gp['GroupName'] || @gp['GroupId']
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
data/lib/renderer/all.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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
|
data/lib/renderer/graphviz.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require 'graphviz'
|
|
2
|
-
|
|
3
|
-
module Renderer
|
|
4
|
-
class GraphViz
|
|
5
|
-
def initialize(file_name, config)
|
|
6
|
-
@g = Graphviz::Graph.new('G', **{
|
|
7
|
-
overlap: false,
|
|
8
|
-
splines: true,
|
|
9
|
-
sep: 1,
|
|
10
|
-
concentrate: true,
|
|
11
|
-
rankdir: "LR"
|
|
12
|
-
})
|
|
13
|
-
@file_name = file_name
|
|
14
|
-
@config = config
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def add_node(name, opts)
|
|
18
|
-
@g.add_node(name, label: name)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def add_edge(from, to, opts)
|
|
22
|
-
from_node = create_if_missing(from)
|
|
23
|
-
to_node = create_if_missing(to)
|
|
24
|
-
options = ({style: 'bold'}).merge(opts)
|
|
25
|
-
from_node.connect(to_node, options)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def create_if_missing(name)
|
|
29
|
-
n = @g.get_node(name).first
|
|
30
|
-
n.nil? ? add_node(name, {}) : n
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def output
|
|
34
|
-
Graphviz::output(@g, path: @file_name, format: nil) #format: nil to force detection based on extension.
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
data/lib/renderer/json.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module Renderer
|
|
2
|
-
class Json
|
|
3
|
-
def initialize(file_name, config)
|
|
4
|
-
@nodes = []
|
|
5
|
-
@edges = []
|
|
6
|
-
@file_name = file_name
|
|
7
|
-
@config = config
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def add_node(name, opts)
|
|
11
|
-
@nodes << {id: name, label: name}
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def add_edge(from, to, opts)
|
|
15
|
-
@edges << {id: "#{from}-#{to}", source: from, target: to, label: opts[:label]}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def output
|
|
19
|
-
IO.write(@file_name, {nodes: @nodes, edges: @edges}.to_json)
|
|
20
|
-
Renderer.copy_asset('view.html', @file_name)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
data/lib/renderer/navigator.rb
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
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
|
-
info = "<b>Security group</b>: #{name}, <br/><b>VPC:</b> #{vpc}"
|
|
16
|
-
@nodes << {id: name, label: name, categories: [vpc], info: info}
|
|
17
|
-
@categories.add(vpc)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def add_edge(from, to, opts)
|
|
21
|
-
@edges << {id: "#{from}-#{to}", from: from, to: to, label: opts[:label]}
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def output
|
|
25
|
-
IO.write(@file_name, {
|
|
26
|
-
data: {nodes: @nodes, edges: @edges},
|
|
27
|
-
categories: Hash[@categories.map{|c| [c, c]}]
|
|
28
|
-
}.to_json)
|
|
29
|
-
Renderer.copy_asset('navigator.html', @file_name)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
data/lib/version.rb
DELETED
data/spec/color_picker_spec.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe ColorPicker do
|
|
4
|
-
context 'default picker' do
|
|
5
|
-
let(:picker) { ColorPicker.new(false) }
|
|
6
|
-
|
|
7
|
-
it 'should add default colors for edges' do
|
|
8
|
-
expect(picker.color(0, true)).to eq(:blue)
|
|
9
|
-
expect(picker.color(0, false)).to eq(:red)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
context 'color picker' do
|
|
13
|
-
let(:picker) { ColorPicker.new(true) }
|
|
14
|
-
|
|
15
|
-
it 'should add default colors for edges' do
|
|
16
|
-
expect(picker.color(0, 'ignore')).to eq('#00004c')
|
|
17
|
-
expect(picker.color(10000, 'ignore')).to eq('#C76F5B')
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
data/spec/graph_filter_spec.rb
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'ostruct'
|
|
3
|
-
|
|
4
|
-
describe GraphFilter do
|
|
5
|
-
it 'should include nodes reachable from source' do
|
|
6
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[1, 2, 2, 3, 2, 4, 4, 5])
|
|
7
|
-
|
|
8
|
-
expect(graph.filter(2, nil).to_s).to eq('(2-3)(2-4)(4-5)')
|
|
9
|
-
end
|
|
10
|
-
it 'should remove nodes not reachable from source' do
|
|
11
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[1, 2, 2, 3, 2, 4, 4, 5, 3, 5])
|
|
12
|
-
|
|
13
|
-
expect(graph.filter(3, nil).to_s).to eq('(3-5)')
|
|
14
|
-
end
|
|
15
|
-
it 'should remove nodes not reachable to destination' do
|
|
16
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
17
|
-
1, 2,
|
|
18
|
-
1, 3,
|
|
19
|
-
1, 4,
|
|
20
|
-
2, 3,
|
|
21
|
-
2, 4,
|
|
22
|
-
3, 4,
|
|
23
|
-
])
|
|
24
|
-
|
|
25
|
-
expect(graph.filter(nil, 3).to_s).to eq('(1-2)(1-3)(2-3)')
|
|
26
|
-
end
|
|
27
|
-
it 'should remove nodes not reachable to destination from source' do
|
|
28
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
29
|
-
1, 2,
|
|
30
|
-
1, 3,
|
|
31
|
-
1, 4,
|
|
32
|
-
2, 3,
|
|
33
|
-
2, 4,
|
|
34
|
-
])
|
|
35
|
-
|
|
36
|
-
expect(graph.filter(2, 4).to_s).to eq('(2-4)')
|
|
37
|
-
end
|
|
38
|
-
it 'should retain edges which pass through intermediate nodes' do
|
|
39
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
40
|
-
1, 2,
|
|
41
|
-
1, 3,
|
|
42
|
-
1, 4,
|
|
43
|
-
2, 3,
|
|
44
|
-
2, 4,
|
|
45
|
-
3, 4,
|
|
46
|
-
])
|
|
47
|
-
expect(graph.filter(2, 4).to_s).to eq('(2-3)(2-4)(3-4)')
|
|
48
|
-
end
|
|
49
|
-
it 'should remove nodes not reachable to destination from source #1' do
|
|
50
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
51
|
-
1, 2,
|
|
52
|
-
1, 3,
|
|
53
|
-
1, 4,
|
|
54
|
-
2, 3,
|
|
55
|
-
2, 4,
|
|
56
|
-
3, 5,
|
|
57
|
-
5, 4
|
|
58
|
-
])
|
|
59
|
-
expect(graph.filter(1, 5).to_s).to eq('(1-2)(1-3)(2-3)(3-5)')
|
|
60
|
-
end
|
|
61
|
-
it 'should remove nodes not reachable to destination from source #2' do
|
|
62
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
63
|
-
1, 2,
|
|
64
|
-
1, 3,
|
|
65
|
-
1, 4,
|
|
66
|
-
2, 3,
|
|
67
|
-
2, 4,
|
|
68
|
-
3, 5,
|
|
69
|
-
5, 4
|
|
70
|
-
])
|
|
71
|
-
expect(graph.filter(1, 4).to_s).to eq('(1-2)(1-3)(1-4)(2-3)(2-4)(3-5)(5-4)')
|
|
72
|
-
end
|
|
73
|
-
it 'should remove nodes not reachable to destination from source #3' do
|
|
74
|
-
graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
|
|
75
|
-
1, 2,
|
|
76
|
-
1, 3,
|
|
77
|
-
1, 4,
|
|
78
|
-
2, 3,
|
|
79
|
-
2, 4,
|
|
80
|
-
3, 5,
|
|
81
|
-
5, 4
|
|
82
|
-
])
|
|
83
|
-
expect(graph.filter(2, 4).to_s).to eq('(2-3)(2-4)(3-5)(5-4)')
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"nodes":[{"id":"asv-app","label":"asv-app"},{"id":"asv-bastion","label":"asv-bastion"},{"id":"*","label":"*"},{"id":"asv-db","label":"asv-db"},{"id":"asv-solr","label":"asv-solr"},{"id":"default","label":"default"}],"edges":[{"id":"asv-bastion-asv-app","source":"asv-bastion","target":"asv-app","label":"22/tcp"},{"id":"*-asv-app","source":"*","target":"asv-app","label":"80/tcp"},{"id":"*-asv-bastion","source":"*","target":"asv-bastion","label":"22/tcp"},{"id":"asv-app-asv-db","source":"asv-app","target":"asv-db","label":"5432/tcp"},{"id":"asv-bastion-asv-db","source":"asv-bastion","target":"asv-db","label":"22/tcp"},{"id":"asv-app-asv-solr","source":"asv-app","target":"asv-solr","label":"8983/tcp"},{"id":"asv-bastion-asv-solr","source":"asv-bastion","target":"asv-solr","label":"22/tcp"},{"id":"default-default","source":"default","target":"default","label":"*"},{"id":"*-default","source":"*","target":"default","label":"22/tcp"},{"id":"default-*","source":"default","target":"*","label":"*"}]}
|