fluent-plugin-ssl-check 2.3.0 → 2.4.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/.gitlab-ci.yml +10 -0
- data/.rubocop.yml +4 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +5 -1
- data/README.md +33 -0
- data/fluent-plugin-ssl-check.gemspec +2 -1
- data/lib/fluent/plugin/in_ssl_check.rb +8 -119
- data/lib/fluent/plugin/in_ssl_file_check.rb +104 -0
- data/lib/fluent/plugin/ssl_check/file_checker.rb +51 -0
- data/lib/fluent/plugin/ssl_check/ssl_common.rb +19 -0
- data/lib/fluent/plugin/ssl_check/ssl_info.rb +75 -0
- data/lib/fluent/plugin/ssl_check/ssl_input_emit.rb +63 -0
- data/lib/fluent/plugin/ssl_check.rb +13 -0
- metadata +30 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32576d289dd8aa0e769f4e4aaa975cbc0517d3d25a70506f5ef478572ca7cf89
|
4
|
+
data.tar.gz: ac1682153f0c68ed33aec0ad1334776425d542369fa0285a6c306dc1892c72e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4702ea39635a4f00dce824ca750a5c9b507a1102234b88b3fe782bd25205c7377a40cde8e51143324af1d1f25ee574542e391b8e99f59e9c3fa1d31b15d95cc
|
7
|
+
data.tar.gz: e67001eedef2c25b144ef2f7f63b6af0824279fb84ecbe9bda90005627bd575c1558b69027ec80944804f08f1840f162f65276464e743b41c087e1515d7789fe
|
data/.gitlab-ci.yml
ADDED
data/.rubocop.yml
CHANGED
@@ -22,6 +22,7 @@ Metrics/ClassLength:
|
|
22
22
|
Exclude:
|
23
23
|
- test/**/*.rb
|
24
24
|
- lib/fluent/plugin/in_ssl_check.rb
|
25
|
+
- lib/fluent/plugin/in_ssl_file_check.rb
|
25
26
|
|
26
27
|
Metrics/MethodLength:
|
27
28
|
Max: 20
|
@@ -29,3 +30,6 @@ Metrics/MethodLength:
|
|
29
30
|
# Naming/MethodParameterName:
|
30
31
|
# Exclude:
|
31
32
|
# - lib/fluent/plugin/in_ssl_check.rb
|
33
|
+
|
34
|
+
Style/Documentation:
|
35
|
+
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.3.6
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-plugin-ssl-check (2.
|
4
|
+
fluent-plugin-ssl-check (2.4.0)
|
5
5
|
fluentd (>= 0.14.10, < 2)
|
6
6
|
|
7
7
|
GEM
|
@@ -29,6 +29,8 @@ GEM
|
|
29
29
|
json (2.6.3)
|
30
30
|
kwalify (0.7.2)
|
31
31
|
language_server-protocol (3.17.0.3)
|
32
|
+
mocha (2.6.1)
|
33
|
+
ruby2_keywords (>= 0.0.5)
|
32
34
|
msgpack (1.7.2)
|
33
35
|
parallel (1.23.0)
|
34
36
|
parser (3.2.2.3)
|
@@ -61,6 +63,7 @@ GEM
|
|
61
63
|
rubocop-rake (0.6.0)
|
62
64
|
rubocop (~> 1.0)
|
63
65
|
ruby-progressbar (1.13.0)
|
66
|
+
ruby2_keywords (0.0.5)
|
64
67
|
serverengine (2.3.2)
|
65
68
|
sigdump (~> 0.2.2)
|
66
69
|
sigdump (0.2.5)
|
@@ -84,6 +87,7 @@ DEPENDENCIES
|
|
84
87
|
bundler (~> 2.4)
|
85
88
|
byebug (~> 11.1, >= 11.1.3)
|
86
89
|
fluent-plugin-ssl-check!
|
90
|
+
mocha (~> 2.6, >= 2.6.1)
|
87
91
|
rake (~> 13.0, >= 13.0.6)
|
88
92
|
reek (~> 6.1, >= 6.1.4)
|
89
93
|
rubocop (~> 1.56)
|
data/README.md
CHANGED
@@ -36,6 +36,7 @@ Options are:
|
|
36
36
|
* cert: client cert for ssl connection
|
37
37
|
* key: client key associated to client cert for ssl connection
|
38
38
|
* timeout: timeout for ssl check execution (5sec)
|
39
|
+
* paths: local certificate file paths
|
39
40
|
* log_events: emit log format (true)
|
40
41
|
* metric_events: emit metric format (false)
|
41
42
|
* event_prefix: metric event prefix for extra dimension
|
@@ -44,6 +45,38 @@ Options are:
|
|
44
45
|
If no port is specified with host, default port is 443.
|
45
46
|
|
46
47
|
|
48
|
+
### in - ssl_file_check
|
49
|
+
|
50
|
+
Poll ssl local file and report status.
|
51
|
+
|
52
|
+
Example:
|
53
|
+
|
54
|
+
``` conf
|
55
|
+
<source>
|
56
|
+
@type ssl_file_check
|
57
|
+
tag ssl_check
|
58
|
+
|
59
|
+
paths /etc/cert/host.pem,/app/application_1/cert.pem
|
60
|
+
|
61
|
+
interval 600
|
62
|
+
|
63
|
+
ca_path /my/ca_dir/
|
64
|
+
ca_file /my/ca_file
|
65
|
+
</source>
|
66
|
+
```
|
67
|
+
|
68
|
+
Options are:
|
69
|
+
* tag: Tag to emit events on
|
70
|
+
* interval: check every X seconds
|
71
|
+
* paths: local certificate file paths
|
72
|
+
* ca_path: directory that contains CA files
|
73
|
+
* ca_file: specify a CA file directly
|
74
|
+
* log_events: emit log format (true)
|
75
|
+
* metric_events: emit metric format (false)
|
76
|
+
* event_prefix: metric event prefix for extra dimension
|
77
|
+
* timestamp_format: iso, epochmillis timestamp format (iso)
|
78
|
+
|
79
|
+
|
47
80
|
## output examples
|
48
81
|
|
49
82
|
### log output example
|
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'fluent-plugin-ssl-check'
|
8
|
-
spec.version = '2.
|
8
|
+
spec.version = '2.4.0'
|
9
9
|
spec.authors = ['Thomas Tych']
|
10
10
|
spec.email = ['thomas.tych@gmail.com']
|
11
11
|
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'bump', '~> 0.10.0'
|
28
28
|
spec.add_development_dependency 'bundler', '~> 2.4'
|
29
29
|
spec.add_development_dependency 'byebug', '~> 11.1', '>= 11.1.3'
|
30
|
+
spec.add_development_dependency 'mocha', '~> 2.6', '>= 2.6.1'
|
30
31
|
spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6'
|
31
32
|
spec.add_development_dependency 'reek', '~> 6.1', '>= 6.1.4'
|
32
33
|
spec.add_development_dependency 'rubocop', '~> 1.56'
|
@@ -23,15 +23,17 @@ require 'timeout'
|
|
23
23
|
require 'date'
|
24
24
|
|
25
25
|
require_relative 'extensions/time'
|
26
|
+
require_relative 'ssl_check'
|
26
27
|
|
27
28
|
module Fluent
|
28
29
|
module Plugin
|
29
|
-
# ssl_check input plugin
|
30
|
-
# check ssl service
|
31
30
|
class SslCheckInput < Fluent::Plugin::Input
|
32
31
|
NAME = 'ssl_check'
|
33
32
|
Fluent::Plugin.register_input(NAME, self)
|
34
33
|
|
34
|
+
include Fluent::Plugin::SslCheck::SslInputEmit
|
35
|
+
include Fluent::Plugin::SslCheck::SslCommon
|
36
|
+
|
35
37
|
DEFAULT_TAG = NAME
|
36
38
|
DEFAULT_PORT = 443
|
37
39
|
DEFAULT_INTERVAL = 600
|
@@ -41,6 +43,7 @@ module Fluent
|
|
41
43
|
DEFAULT_LOG_EVENTS = true
|
42
44
|
DEFAULT_METRIC_EVENTS = false
|
43
45
|
DEFAULT_EVENT_PREFIX = ''
|
46
|
+
DEFAULT_TIMESTAMP_FORMAT = :iso
|
44
47
|
|
45
48
|
desc 'Tag to emit events on'
|
46
49
|
config_param :tag, :string, default: DEFAULT_TAG
|
@@ -72,7 +75,7 @@ module Fluent
|
|
72
75
|
desc 'Event prefix'
|
73
76
|
config_param :event_prefix, :string, default: DEFAULT_EVENT_PREFIX
|
74
77
|
desc 'Timestamp format'
|
75
|
-
config_param :timestamp_format, :enum, list: %i[iso epochmillis], default:
|
78
|
+
config_param :timestamp_format, :enum, list: %i[iso epochmillis], default: DEFAULT_TIMESTAMP_FORMAT
|
76
79
|
|
77
80
|
helpers :timer
|
78
81
|
|
@@ -125,57 +128,6 @@ module Fluent
|
|
125
128
|
ssl_client.ssl_info
|
126
129
|
end
|
127
130
|
|
128
|
-
def emit_logs(ssl_info)
|
129
|
-
record = {
|
130
|
-
'timestamp' => ssl_info.time.send("to_#{timestamp_format}"),
|
131
|
-
'status' => ssl_info.status,
|
132
|
-
'host' => ssl_info.host,
|
133
|
-
'port' => ssl_info.port,
|
134
|
-
'ssl_version' => ssl_info.ssl_version,
|
135
|
-
'ssl_dn' => ssl_info.subject_s,
|
136
|
-
'ssl_not_after' => ssl_info.not_after,
|
137
|
-
'expire_in_days' => ssl_info.expire_in_days,
|
138
|
-
'serial' => ssl_info.serial
|
139
|
-
}
|
140
|
-
record.update('error_class' => ssl_info.error_class) if ssl_info.error_class
|
141
|
-
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
142
|
-
end
|
143
|
-
|
144
|
-
def emit_metrics(ssl_info)
|
145
|
-
emit_metric_status(ssl_info)
|
146
|
-
emit_metric_expirency(ssl_info)
|
147
|
-
end
|
148
|
-
|
149
|
-
def emit_metric_status(ssl_info)
|
150
|
-
record = {
|
151
|
-
'timestamp' => ssl_info.time.send("to_#{timestamp_format}"),
|
152
|
-
'metric_name' => 'ssl_status',
|
153
|
-
'metric_value' => ssl_info.status,
|
154
|
-
"#{event_prefix}host" => ssl_info.host,
|
155
|
-
"#{event_prefix}port" => ssl_info.port,
|
156
|
-
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
157
|
-
"#{event_prefix}ssl_version" => ssl_info.ssl_version,
|
158
|
-
"#{event_prefix}ssl_not_after" => ssl_info.not_after,
|
159
|
-
"#{event_prefix}serial" => ssl_info.serial
|
160
|
-
}
|
161
|
-
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
162
|
-
end
|
163
|
-
|
164
|
-
def emit_metric_expirency(ssl_info)
|
165
|
-
return if ssl_info.error
|
166
|
-
|
167
|
-
record = {
|
168
|
-
'timestamp' => ssl_info.time.send("to_#{timestamp_format}"),
|
169
|
-
'metric_name' => 'ssl_expirency',
|
170
|
-
'metric_value' => ssl_info.expire_in_days,
|
171
|
-
"#{event_prefix}host" => ssl_info.host,
|
172
|
-
"#{event_prefix}port" => ssl_info.port,
|
173
|
-
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
174
|
-
"#{event_prefix}serial" => ssl_info.serial
|
175
|
-
}
|
176
|
-
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
177
|
-
end
|
178
|
-
|
179
131
|
private
|
180
132
|
|
181
133
|
def ssl_verify_mode
|
@@ -184,61 +136,6 @@ module Fluent
|
|
184
136
|
OpenSSL::SSL::VERIFY_NONE
|
185
137
|
end
|
186
138
|
|
187
|
-
# ssl info
|
188
|
-
# to encapsulate extracted ssl information
|
189
|
-
class SslInfo
|
190
|
-
OK = 1
|
191
|
-
KO = 0
|
192
|
-
|
193
|
-
attr_reader :time
|
194
|
-
attr_accessor :host, :port, :cert, :cert_chain, :ssl_version, :error
|
195
|
-
|
196
|
-
# rubocop:disable Metrics/ParameterLists
|
197
|
-
def initialize(host: nil, port: nil, cert: nil, cert_chain: nil, ssl_version: nil, error: nil, time: Time.now)
|
198
|
-
@host = host
|
199
|
-
@port = port
|
200
|
-
@cert = cert
|
201
|
-
@cert_chain = cert_chain
|
202
|
-
@ssl_version = ssl_version
|
203
|
-
@error = error
|
204
|
-
@time = time
|
205
|
-
end
|
206
|
-
# rubocop:enable Metrics/ParameterLists
|
207
|
-
|
208
|
-
def subject_s
|
209
|
-
cert.subject.to_s if cert&.subject
|
210
|
-
end
|
211
|
-
|
212
|
-
def expire_in_days
|
213
|
-
return unless cert&.not_after
|
214
|
-
|
215
|
-
expire_in = cert.not_after
|
216
|
-
((expire_in - time) / 3600 / 24).to_i
|
217
|
-
end
|
218
|
-
|
219
|
-
def not_after
|
220
|
-
return unless cert
|
221
|
-
|
222
|
-
cert.not_after.iso8601(3)
|
223
|
-
end
|
224
|
-
|
225
|
-
def serial
|
226
|
-
cert&.serial&.to_s(16)&.downcase
|
227
|
-
end
|
228
|
-
|
229
|
-
def status
|
230
|
-
return KO if error
|
231
|
-
|
232
|
-
OK
|
233
|
-
end
|
234
|
-
|
235
|
-
def error_class
|
236
|
-
return unless error
|
237
|
-
|
238
|
-
error.class.to_s
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
139
|
# ssl client
|
243
140
|
# to check ssl status
|
244
141
|
class SslClient
|
@@ -261,7 +158,7 @@ module Fluent
|
|
261
158
|
# rubocop:enable Metrics/ParameterLists
|
262
159
|
|
263
160
|
def ssl_info
|
264
|
-
info = SslInfo.new(host: host, port: port)
|
161
|
+
info = Fluent::Plugin::SslCheck::SslInfo.new(host: host, port: port)
|
265
162
|
begin
|
266
163
|
Timeout.timeout(timeout) do
|
267
164
|
tcp_socket = TCPSocket.open(host, port)
|
@@ -282,18 +179,10 @@ module Fluent
|
|
282
179
|
info
|
283
180
|
end
|
284
181
|
|
285
|
-
def store
|
286
|
-
OpenSSL::X509::Store.new.tap do |store|
|
287
|
-
store.set_default_paths
|
288
|
-
store.add_path(ca_path) if ca_path
|
289
|
-
store.add_file(ca_file) if ca_file
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
182
|
def ssl_context
|
294
183
|
OpenSSL::SSL::SSLContext.new.tap do |ssl_context|
|
295
184
|
ssl_context.verify_mode = verify_mode
|
296
|
-
ssl_context.cert_store =
|
185
|
+
ssl_context.cert_store = ssl_store(ca_path: ca_path, ca_file: ca_file)
|
297
186
|
ssl_context.min_version = nil
|
298
187
|
ssl_context.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
299
188
|
ssl_context.cert = OpenSSL::X509::Certificate.new(File.open(cert)) if cert
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright 2024- Thomas Tych
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'fluent/plugin/input'
|
19
|
+
|
20
|
+
require 'openssl'
|
21
|
+
|
22
|
+
require_relative 'extensions/time'
|
23
|
+
require_relative 'ssl_check'
|
24
|
+
|
25
|
+
module Fluent
|
26
|
+
module Plugin
|
27
|
+
class SslFileCheckInput < Fluent::Plugin::Input
|
28
|
+
NAME = 'ssl_file_check'
|
29
|
+
Fluent::Plugin.register_input(NAME, self)
|
30
|
+
|
31
|
+
include Fluent::Plugin::SslCheck::SslInputEmit
|
32
|
+
|
33
|
+
DEFAULT_TAG = NAME
|
34
|
+
DEFAULT_INTERVAL = 600
|
35
|
+
DEFAULT_LOG_EVENTS = true
|
36
|
+
DEFAULT_METRIC_EVENTS = false
|
37
|
+
DEFAULT_EVENT_PREFIX = ''
|
38
|
+
DEFAULT_TIMESTAMP_FORMAT = :iso
|
39
|
+
|
40
|
+
desc 'Tag to emit events on'
|
41
|
+
config_param :tag, :string, default: DEFAULT_TAG
|
42
|
+
|
43
|
+
desc 'Paths of local certificate to check'
|
44
|
+
config_param :paths, :array, default: [], value_type: :string
|
45
|
+
|
46
|
+
desc 'Interval for the check execution'
|
47
|
+
config_param :interval, :time, default: DEFAULT_INTERVAL
|
48
|
+
|
49
|
+
desc 'CA path to load'
|
50
|
+
config_param :ca_path, :string, default: nil
|
51
|
+
desc 'CA file to load'
|
52
|
+
config_param :ca_file, :string, default: nil
|
53
|
+
|
54
|
+
desc 'Emit log events'
|
55
|
+
config_param :log_events, :bool, default: DEFAULT_LOG_EVENTS
|
56
|
+
desc 'Emit metric events'
|
57
|
+
config_param :metric_events, :bool, default: DEFAULT_METRIC_EVENTS
|
58
|
+
desc 'Event prefix'
|
59
|
+
config_param :event_prefix, :string, default: DEFAULT_EVENT_PREFIX
|
60
|
+
desc 'Timestamp format'
|
61
|
+
config_param :timestamp_format, :enum, list: %i[iso epochmillis], default: DEFAULT_TIMESTAMP_FORMAT
|
62
|
+
|
63
|
+
helpers :timer
|
64
|
+
|
65
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
66
|
+
def configure(conf)
|
67
|
+
super
|
68
|
+
|
69
|
+
raise Fluent::ConfigError, 'tag can not be empty.' if !tag || tag.empty?
|
70
|
+
raise Fluent::ConfigError, 'paths can not be empty.' unless paths
|
71
|
+
raise Fluent::ConfigError, 'interval can not be < 1.' if !interval || interval < 1
|
72
|
+
raise Fluent::ConfigError, 'ca_path should be a dir.' if ca_path && !File.directory?(ca_path)
|
73
|
+
raise Fluent::ConfigError, 'ca_file should be a file.' if ca_file && !File.file?(ca_file)
|
74
|
+
|
75
|
+
log.warn("#{NAME}: paths is empty, nothing to process") if paths.empty?
|
76
|
+
end
|
77
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
78
|
+
|
79
|
+
def start
|
80
|
+
super
|
81
|
+
|
82
|
+
timer_execute(:ssl_file_check_timer, 1, repeat: false, &method(:check)) if interval > 60
|
83
|
+
|
84
|
+
timer_execute(:ssl_file_check_timer, interval, repeat: true, &method(:check))
|
85
|
+
end
|
86
|
+
|
87
|
+
# rubocop:disable Lint/SuppressedException
|
88
|
+
def check
|
89
|
+
paths.each do |cert_path|
|
90
|
+
ssl_info = fetch_ssl_info(cert_path)
|
91
|
+
emit_logs(ssl_info) if log_events
|
92
|
+
emit_metrics(ssl_info) if metric_events
|
93
|
+
rescue StandardError
|
94
|
+
end
|
95
|
+
end
|
96
|
+
# rubocop:enable Lint/SuppressedException
|
97
|
+
|
98
|
+
def fetch_ssl_info(filepath)
|
99
|
+
ssl_file = Fluent::Plugin::SslCheck::FileChecker.new(filepath, ca_path: ca_path, ca_file: ca_file)
|
100
|
+
ssl_file.ssl_info
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'openssl'
|
5
|
+
require_relative 'ssl_common'
|
6
|
+
require_relative 'ssl_info'
|
7
|
+
|
8
|
+
module Fluent
|
9
|
+
module Plugin
|
10
|
+
module SslCheck
|
11
|
+
class FileChecker
|
12
|
+
attr_reader :filepath, :ca_path, :ca_file
|
13
|
+
|
14
|
+
include Fluent::Plugin::SslCheck::SslCommon
|
15
|
+
|
16
|
+
def initialize(filepath, ca_path: nil, ca_file: nil)
|
17
|
+
@filepath = filepath
|
18
|
+
@ca_path = ca_path
|
19
|
+
@ca_file = ca_file
|
20
|
+
end
|
21
|
+
|
22
|
+
def certificate
|
23
|
+
@certificate ||= OpenSSL::X509::Certificate.new(File.read(filepath_absolute))
|
24
|
+
end
|
25
|
+
|
26
|
+
def filepath_absolute
|
27
|
+
File.expand_path(filepath)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ssl_info
|
31
|
+
info = Fluent::Plugin::SslCheck::SslInfo.new(host: hostname, path: filepath_absolute)
|
32
|
+
begin
|
33
|
+
ca_store = ssl_store(ca_path: ca_path, ca_file: ca_file)
|
34
|
+
ca_store.verify(certificate)
|
35
|
+
|
36
|
+
info.cert = certificate
|
37
|
+
info.cert_chain = ca_store.chain
|
38
|
+
info.error = ca_store.error_string if ca_store.error != 0
|
39
|
+
rescue StandardError => e
|
40
|
+
info.error = e
|
41
|
+
end
|
42
|
+
info
|
43
|
+
end
|
44
|
+
|
45
|
+
def hostname
|
46
|
+
Socket.gethostname
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Fluent
|
6
|
+
module Plugin
|
7
|
+
module SslCheck
|
8
|
+
module SslCommon
|
9
|
+
def ssl_store(ca_path: nil, ca_file: nil)
|
10
|
+
OpenSSL::X509::Store.new.tap do |store|
|
11
|
+
store.set_default_paths
|
12
|
+
store.add_path(ca_path) if ca_path
|
13
|
+
store.add_file(ca_file) if ca_file
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Fluent
|
6
|
+
module Plugin
|
7
|
+
module SslCheck
|
8
|
+
# ssl info
|
9
|
+
# to encapsulate extracted ssl information
|
10
|
+
class SslInfo
|
11
|
+
OK = 1
|
12
|
+
KO = 0
|
13
|
+
|
14
|
+
attr_accessor :host, :port, :path, :cert, :cert_chain, :ssl_version, :error
|
15
|
+
|
16
|
+
# rubocop:disable Metrics/ParameterLists
|
17
|
+
def initialize(host: nil, port: nil, path: nil, cert: nil, cert_chain: nil, ssl_version: nil,
|
18
|
+
error: nil, time: nil)
|
19
|
+
@host = host
|
20
|
+
@port = port
|
21
|
+
@path = path
|
22
|
+
@cert = cert
|
23
|
+
@cert_chain = cert_chain
|
24
|
+
@ssl_version = ssl_version
|
25
|
+
@error = error
|
26
|
+
@time = time
|
27
|
+
end
|
28
|
+
# rubocop:enable Metrics/ParameterLists
|
29
|
+
|
30
|
+
def subject_s
|
31
|
+
cert.subject.to_utf8 if cert&.subject
|
32
|
+
end
|
33
|
+
|
34
|
+
def expire_in_days
|
35
|
+
return unless cert&.not_after
|
36
|
+
|
37
|
+
expire_in = cert.not_after
|
38
|
+
((expire_in - time) / 3600 / 24).to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def not_after
|
42
|
+
return unless cert
|
43
|
+
|
44
|
+
cert.not_after.iso8601(3)
|
45
|
+
end
|
46
|
+
|
47
|
+
def serial
|
48
|
+
cert&.serial&.to_s(16)&.downcase
|
49
|
+
end
|
50
|
+
|
51
|
+
def status
|
52
|
+
return KO if error
|
53
|
+
|
54
|
+
OK
|
55
|
+
end
|
56
|
+
|
57
|
+
def time
|
58
|
+
@time ||= Time.now.utc
|
59
|
+
end
|
60
|
+
|
61
|
+
def time_utc
|
62
|
+
time.utc
|
63
|
+
end
|
64
|
+
|
65
|
+
def error_class
|
66
|
+
return unless error
|
67
|
+
|
68
|
+
return error if error.is_a?(String)
|
69
|
+
|
70
|
+
error.class.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fluent
|
4
|
+
module Plugin
|
5
|
+
module SslCheck
|
6
|
+
module SslInputEmit
|
7
|
+
def emit_logs(ssl_info)
|
8
|
+
record = {
|
9
|
+
'timestamp' => ssl_info.time_utc.send("to_#{timestamp_format}"),
|
10
|
+
'status' => ssl_info.status,
|
11
|
+
'host' => ssl_info.host,
|
12
|
+
'port' => ssl_info.port,
|
13
|
+
'path' => ssl_info.path,
|
14
|
+
'ssl_version' => ssl_info.ssl_version,
|
15
|
+
'ssl_dn' => ssl_info.subject_s,
|
16
|
+
'ssl_not_after' => ssl_info.not_after,
|
17
|
+
'expire_in_days' => ssl_info.expire_in_days,
|
18
|
+
'serial' => ssl_info.serial
|
19
|
+
}
|
20
|
+
record.update('error_class' => ssl_info.error_class) if ssl_info.error_class
|
21
|
+
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time_utc), record)
|
22
|
+
end
|
23
|
+
|
24
|
+
def emit_metrics(ssl_info)
|
25
|
+
emit_metric_status(ssl_info)
|
26
|
+
emit_metric_expirency(ssl_info)
|
27
|
+
end
|
28
|
+
|
29
|
+
def emit_metric_status(ssl_info)
|
30
|
+
record = {
|
31
|
+
'timestamp' => ssl_info.time_utc.send("to_#{timestamp_format}"),
|
32
|
+
'metric_name' => 'ssl_status',
|
33
|
+
'metric_value' => ssl_info.status,
|
34
|
+
"#{event_prefix}host" => ssl_info.host,
|
35
|
+
"#{event_prefix}port" => ssl_info.port,
|
36
|
+
"#{event_prefix}path" => ssl_info.path,
|
37
|
+
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
38
|
+
"#{event_prefix}ssl_version" => ssl_info.ssl_version,
|
39
|
+
"#{event_prefix}ssl_not_after" => ssl_info.not_after,
|
40
|
+
"#{event_prefix}serial" => ssl_info.serial
|
41
|
+
}
|
42
|
+
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time_utc), record)
|
43
|
+
end
|
44
|
+
|
45
|
+
def emit_metric_expirency(ssl_info)
|
46
|
+
return unless ssl_info.cert
|
47
|
+
|
48
|
+
record = {
|
49
|
+
'timestamp' => ssl_info.time_utc.send("to_#{timestamp_format}"),
|
50
|
+
'metric_name' => 'ssl_expirency',
|
51
|
+
'metric_value' => ssl_info.expire_in_days,
|
52
|
+
"#{event_prefix}host" => ssl_info.host,
|
53
|
+
"#{event_prefix}port" => ssl_info.port,
|
54
|
+
"#{event_prefix}path" => ssl_info.path,
|
55
|
+
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
56
|
+
"#{event_prefix}serial" => ssl_info.serial
|
57
|
+
}
|
58
|
+
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time_utc), record)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'ssl_check/ssl_input_emit'
|
4
|
+
require_relative 'ssl_check/ssl_common'
|
5
|
+
require_relative 'ssl_check/ssl_info'
|
6
|
+
require_relative 'ssl_check/file_checker'
|
7
|
+
|
8
|
+
module Fluent
|
9
|
+
module Plugin
|
10
|
+
module SslCheck
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-ssl-check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Tych
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bump
|
@@ -58,6 +58,26 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: 11.1.3
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: mocha
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '2.6'
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.6.1
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.6'
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.6.1
|
61
81
|
- !ruby/object:Gem::Dependency
|
62
82
|
name: rake
|
63
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,6 +208,7 @@ extensions: []
|
|
188
208
|
extra_rdoc_files: []
|
189
209
|
files:
|
190
210
|
- ".gitignore"
|
211
|
+
- ".gitlab-ci.yml"
|
191
212
|
- ".rubocop.yml"
|
192
213
|
- ".ruby-version"
|
193
214
|
- Gemfile
|
@@ -198,6 +219,12 @@ files:
|
|
198
219
|
- fluent-plugin-ssl-check.gemspec
|
199
220
|
- lib/fluent/plugin/extensions/time.rb
|
200
221
|
- lib/fluent/plugin/in_ssl_check.rb
|
222
|
+
- lib/fluent/plugin/in_ssl_file_check.rb
|
223
|
+
- lib/fluent/plugin/ssl_check.rb
|
224
|
+
- lib/fluent/plugin/ssl_check/file_checker.rb
|
225
|
+
- lib/fluent/plugin/ssl_check/ssl_common.rb
|
226
|
+
- lib/fluent/plugin/ssl_check/ssl_info.rb
|
227
|
+
- lib/fluent/plugin/ssl_check/ssl_input_emit.rb
|
201
228
|
homepage: https://gitlab.com/ttych/fluent-plugin-ssl-check
|
202
229
|
licenses:
|
203
230
|
- Apache-2.0
|
@@ -218,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
218
245
|
- !ruby/object:Gem::Version
|
219
246
|
version: '0'
|
220
247
|
requirements: []
|
221
|
-
rubygems_version: 3.
|
248
|
+
rubygems_version: 3.5.22
|
222
249
|
signing_key:
|
223
250
|
specification_version: 4
|
224
251
|
summary: fluentd plugin to check ssl endpoint
|