torizon_audit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/torizon_audit.rb +147 -0
- metadata +43 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 500ba44874ca4f8acf49a1b7f16d861353cf049be7be4b0518689a722d4277ed
|
4
|
+
data.tar.gz: dee0a4946b52cb837bc847bd87d91d6baf0b13672726400e6917891939ddef92
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb17aabf9a1ef454d77df1afdd2a5f75254fd910b54862a063a05322192af17ff05f9dfc3b192ec728f04559385ba060d2537a4390df8ab0398a47f9c751863f
|
7
|
+
data.tar.gz: 9b8b2345dedd9f1a0f3d7140c16a9bfa46b8c6aee3885fc1217ea642253b65cf356d099d9d4391d54225ef7198b9d9976fd3d5bd68f25f5a16fc1d0930f7a242
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "optparse"
|
3
|
+
require "optparse/time"
|
4
|
+
require "json"
|
5
|
+
require "elasticsearch"
|
6
|
+
|
7
|
+
|
8
|
+
class Query
|
9
|
+
def self.timeFormat(t)
|
10
|
+
return t.strftime("%Y-%m-%dT%0k:%0M:%0SZ")
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.matchQuery(key, value, analyzer="standard", operator="OR")
|
14
|
+
return {
|
15
|
+
"match" => {
|
16
|
+
key => {
|
17
|
+
"query" => value,
|
18
|
+
"analyzer" => analyzer,
|
19
|
+
"operator" => operator
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(maxNumLogs = 10000)
|
26
|
+
@query = {
|
27
|
+
"from" => 0,
|
28
|
+
"size" => maxNumLogs,
|
29
|
+
"query" => {
|
30
|
+
"bool" => {
|
31
|
+
"filter" => [
|
32
|
+
{
|
33
|
+
"range" => {
|
34
|
+
"@timestamp" => {
|
35
|
+
"gte" => "2023-03-13T00:00:00.00Z",
|
36
|
+
"lte" => Query.timeFormat(Time.now),
|
37
|
+
"format" => "strict_date_optional_time"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
]
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
def timeRange(from, to)
|
47
|
+
@query["query"]["bool"]["filter"].find{|h| h.key?("range")}["range"]["@timestamp"]["gte"] = from
|
48
|
+
@query["query"]["bool"]["filter"].find{|h| h.key?("range")}["range"]["@timestamp"]["lte"] = to
|
49
|
+
end
|
50
|
+
|
51
|
+
def httpMethod(method)
|
52
|
+
@query["query"]["bool"]["filter"].append(Query.matchQuery("request_method", method))
|
53
|
+
end
|
54
|
+
|
55
|
+
def appName(name)
|
56
|
+
@query["query"]["bool"]["filter"].append(Query.matchQuery("kubernetes.labels.app", name))
|
57
|
+
end
|
58
|
+
|
59
|
+
def uri(path)
|
60
|
+
@query["query"]["bool"]["filter"].append(Query.matchQuery("uri", path, "standard", "AND"))
|
61
|
+
end
|
62
|
+
|
63
|
+
def originNamespace(namespace)
|
64
|
+
@query["query"]["bool"]["filter"].append(Query.matchQuery("origin_namespace", namespace))
|
65
|
+
end
|
66
|
+
|
67
|
+
def toJson()
|
68
|
+
return @query.to_json
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
@query.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# TODO:
|
77
|
+
# Keys rotated offline (tuf-reposerver, director, keyserver)
|
78
|
+
# PUT, POST, DELETE
|
79
|
+
|
80
|
+
class Audit
|
81
|
+
@@actionsMap = {
|
82
|
+
"api/v1/user_repo/targets$" => {"PUT" => "Upload signed targets.json"},
|
83
|
+
"api/v1/user_repo/targets/.*" => {"PUT" => "Create Tuf Target", "POST" => "Create TUF target", "PATCH" => "Modify TUF target", "DELETE" => "Delete TUF target"},
|
84
|
+
"api/v1/user_repo/trusted-delegations/.*/remote/refresh" => {"PUT" => "Refresh remote delegation"},
|
85
|
+
"api/v1/user_repo/trusted-delegations/.*" => {"PUT" => "Create or modify trusted-delegations"},
|
86
|
+
"api/v1/user_repo/delegations/.*" => {"PUT" => "Create or modify delegation metadata"},
|
87
|
+
"api/v1/multi_target_updates" => {"POST" => "Create multi-target-update"},
|
88
|
+
"api/v1/assignments" => {"POST" => "Create device assignment"},
|
89
|
+
"api/v1/admin/repo/offline-updates/.*" => {"POST" => "Create or modify lockbox", "PUT" => "Create or modify lockbox"},
|
90
|
+
"api/accounts/users/clients$" => {"POST" => "Create third-party API client"},
|
91
|
+
"api/accounts/users/clients/.*" => {"DELETE" => "Revoke third-party API client"},
|
92
|
+
"api/accounts/users/.*/keys/credentials.zip" => {"GET" => "Download credentials.zip"},
|
93
|
+
"api/accounts/organizations/share/.*/users$" => {"POST" => "Share organization with user"},
|
94
|
+
"api/accounts/organizations/share/.*/users/.*" => {"DELETE" => "Revoke organization access for user", "PUT" => "Change organization access level for user"},
|
95
|
+
"api/accounts/devices$" => {"POST" => "Provision device"},
|
96
|
+
"api/v1/device_groups$" => {"POST" => "Create device fleet"},
|
97
|
+
"api/v1/device_groups/.*/devices/.*" => {"POST" => "Add device to fleet", "DELETE" => "Remove device from fleet"},
|
98
|
+
"api/v1/device_groups/.*/rename" => {"PUT" => "Rename device fleet"},
|
99
|
+
"api/v1/device_groups/.*" => {"DELETE" => "Delete device fleet"},
|
100
|
+
"api/v1/devices/.*" => {"DELETE" => "Delete device"},
|
101
|
+
}
|
102
|
+
|
103
|
+
def initialize(client)
|
104
|
+
@client = client
|
105
|
+
end
|
106
|
+
|
107
|
+
def findAction(method, uri)
|
108
|
+
@@actionsMap.each {|uriPattern, methodActions|
|
109
|
+
if uri.match(uriPattern)
|
110
|
+
if methodActions.key?(method)
|
111
|
+
return methodActions[method]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
}
|
115
|
+
return "Unknown Action"
|
116
|
+
end
|
117
|
+
|
118
|
+
def userActions(from, to, namespace, dropUnknownActions = true)
|
119
|
+
query = Query.new()
|
120
|
+
query.timeRange(Query.timeFormat(from), Query.timeFormat(to))
|
121
|
+
query.appName("ota-kong-kong")
|
122
|
+
query.originNamespace(namespace)
|
123
|
+
|
124
|
+
response = @client.search index: 'logstash*', body: query.toJson
|
125
|
+
|
126
|
+
actions = response["hits"]["hits"].map{ |obj|
|
127
|
+
src = obj["_source"]
|
128
|
+
{
|
129
|
+
"method" => src.key?("request_method") ? src["request_method"] : "",
|
130
|
+
"path" => src.key?("uri") ? src["uri"]: "",
|
131
|
+
"at" => src.key?("@timestamp") ? src["@timestamp"]: "",
|
132
|
+
"namespace" => src.key?("namespace") ? src["namespace"]: "",
|
133
|
+
"origin_namespace" => src.key?("origin_namespace") ? src["origin_namespace"]: "",
|
134
|
+
"status_code" => src.key?("status") ? src["status"]: "",
|
135
|
+
"ip" => src.key?("client_addr") ? src["client_addr"]: "",
|
136
|
+
"query" => src.key?("query_string") ? src["query_string"]: "",
|
137
|
+
"log_id" => obj.key?("_id") ? obj["_id"]: "",
|
138
|
+
"action" => self.findAction(src.key?("request_method") ? src["request_method"] : "", src.key?("uri") ? src["uri"]: "")
|
139
|
+
}
|
140
|
+
}
|
141
|
+
if dropUnknownActions
|
142
|
+
return actions.select{|req| req["action"] != "Unknown Action"}
|
143
|
+
end
|
144
|
+
return actions
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
metadata
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: torizon_audit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Clouser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Fetch user actions from torizon platform
|
14
|
+
email: ben.clouser@toradex.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/torizon_audit.rb
|
20
|
+
homepage:
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubygems_version: 3.3.25
|
40
|
+
signing_key:
|
41
|
+
specification_version: 4
|
42
|
+
summary: Fetch user actions from torizon platform
|
43
|
+
test_files: []
|