fluent-plugin-ssl-check 2.1.0 → 2.3.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/.rubocop.yml +0 -3
- data/Gemfile.lock +1 -1
- data/README.md +51 -0
- data/fluent-plugin-ssl-check.gemspec +1 -1
- data/lib/fluent/plugin/in_ssl_check.rb +48 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab7b3def2e942f92cf1b8a1fa46f4c7bafe50fbee692334736e19574849e9911
|
4
|
+
data.tar.gz: 5083966b749ba1407cdce60b33f8952dce4b300c5bd7e33496e1b1e02ae0814a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe0d1bd834d8831a510df5754cb488d2e543fbca465bf3b344312b92f236278fbd75cf972efee0d0ffc45838f4550d09f81dba34fbcbf0445810a831b6fda365
|
7
|
+
data.tar.gz: 8cef76bf6831eae2d1053a99699fc07f31077939bd3bc5ab28a402be4d709f9f4eec53ec9c14e954a01cefd5866a399e4d2ceeb373bd0e94d205023bf0375b3a
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[Fluentd](https://fluentd.org/) input plugin to check ssl service.
|
4
4
|
|
5
|
+
|
5
6
|
## plugins
|
6
7
|
|
7
8
|
### in - ssl_check
|
@@ -30,6 +31,10 @@ Options are:
|
|
30
31
|
* interval: check every X seconds
|
31
32
|
* ca_path: directory that contains CA files
|
32
33
|
* ca_file: specify a CA file directly
|
34
|
+
* sni: want the sni support (true)
|
35
|
+
* verify_mode: none or peer
|
36
|
+
* cert: client cert for ssl connection
|
37
|
+
* key: client key associated to client cert for ssl connection
|
33
38
|
* timeout: timeout for ssl check execution (5sec)
|
34
39
|
* log_events: emit log format (true)
|
35
40
|
* metric_events: emit metric format (false)
|
@@ -38,6 +43,52 @@ Options are:
|
|
38
43
|
|
39
44
|
If no port is specified with host, default port is 443.
|
40
45
|
|
46
|
+
|
47
|
+
## output examples
|
48
|
+
|
49
|
+
### log output example
|
50
|
+
|
51
|
+
``` json
|
52
|
+
{
|
53
|
+
"timestamp": "2023-10-03T09:59:41.580+02:00",
|
54
|
+
"status": 1,
|
55
|
+
"host": "www.google.fr",
|
56
|
+
"port": 443,
|
57
|
+
"ssl_version": "TLSv1.2",
|
58
|
+
"ssl_dn": "/CN=*.google.fr",
|
59
|
+
"ssl_not_after": "2023-11-27T08:25:08.000Z",
|
60
|
+
"expire_in_days": 55,
|
61
|
+
"serial": "4e79dbb13c6b57b309780da2d1edbda4"
|
62
|
+
}
|
63
|
+
```
|
64
|
+
|
65
|
+
### metric output example
|
66
|
+
|
67
|
+
``` json
|
68
|
+
{
|
69
|
+
"timestamp": "2023-10-03T10:06:21.417+02:00",
|
70
|
+
"metric_name": "ssl_status",
|
71
|
+
"metric_value": 1,
|
72
|
+
"host": "www.google.fr",
|
73
|
+
"port": 443,
|
74
|
+
"ssl_dn": "/CN=*.google.fr",
|
75
|
+
"ssl_version": "TLSv1.2",
|
76
|
+
"ssl_not_after": "2023-11-27T08:25:08.000Z",
|
77
|
+
"serial": "4e79dbb13c6b57b309780da2d1edbda4"
|
78
|
+
}
|
79
|
+
|
80
|
+
{
|
81
|
+
"timestamp": "2023-10-03T10:06:21.417+02:00",
|
82
|
+
"metric_name": "ssl_expirency",
|
83
|
+
"metric_value": 55,
|
84
|
+
"host": "www.google.fr",
|
85
|
+
"port": 443,
|
86
|
+
"ssl_dn": "/CN=*.google.fr",
|
87
|
+
"serial": "4e79dbb13c6b57b309780da2d1edbda4"
|
88
|
+
}
|
89
|
+
```
|
90
|
+
|
91
|
+
|
41
92
|
## Installation
|
42
93
|
|
43
94
|
Manual install, by executing:
|
@@ -33,10 +33,10 @@ module Fluent
|
|
33
33
|
Fluent::Plugin.register_input(NAME, self)
|
34
34
|
|
35
35
|
DEFAULT_TAG = NAME
|
36
|
-
DEFAULT_HOST = 'localhost'
|
37
36
|
DEFAULT_PORT = 443
|
38
37
|
DEFAULT_INTERVAL = 600
|
39
38
|
DEFAULT_SNI = true
|
39
|
+
DEFAULT_VERIFY_MODE = :peer
|
40
40
|
DEFAULT_TIMEOUT = 5
|
41
41
|
DEFAULT_LOG_EVENTS = true
|
42
42
|
DEFAULT_METRIC_EVENTS = false
|
@@ -55,6 +55,12 @@ module Fluent
|
|
55
55
|
config_param :ca_file, :string, default: nil
|
56
56
|
desc 'SNI support'
|
57
57
|
config_param :sni, :bool, default: DEFAULT_SNI
|
58
|
+
desc 'Verify mode'
|
59
|
+
config_param :verify_mode, :enum, list: %i[none peer], default: DEFAULT_VERIFY_MODE
|
60
|
+
desc 'Client Cert'
|
61
|
+
config_param :cert, :string, default: nil
|
62
|
+
desc 'Client Key'
|
63
|
+
config_param :key, :string, default: nil
|
58
64
|
|
59
65
|
desc 'Timeout for check'
|
60
66
|
config_param :timeout, :integer, default: DEFAULT_TIMEOUT
|
@@ -70,17 +76,22 @@ module Fluent
|
|
70
76
|
|
71
77
|
helpers :timer
|
72
78
|
|
73
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
79
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Style/DoubleNegation
|
74
80
|
def configure(conf)
|
75
81
|
super
|
76
82
|
|
77
83
|
raise Fluent::ConfigError, 'tag can not be empty.' if !tag || tag.empty?
|
78
|
-
raise Fluent::ConfigError, 'hosts can not be empty.'
|
84
|
+
raise Fluent::ConfigError, 'hosts can not be empty.' unless hosts
|
79
85
|
raise Fluent::ConfigError, 'interval can not be < 1.' if !interval || interval < 1
|
80
86
|
raise Fluent::ConfigError, 'ca_path should be a dir.' if ca_path && !File.directory?(ca_path)
|
81
87
|
raise Fluent::ConfigError, 'ca_file should be a file.' if ca_file && !File.file?(ca_file)
|
88
|
+
raise Fluent::ConfigError, 'cert should be a file.' if cert && !File.file?(cert)
|
89
|
+
raise Fluent::ConfigError, 'key should be a file.' if key && !File.file?(key)
|
90
|
+
raise Fluent::ConfigError, 'cert and key should be specified.' if !!cert ^ !!key
|
91
|
+
|
92
|
+
log.warn("#{NAME}: hosts is empty, nothing to process") if hosts.empty?
|
82
93
|
end
|
83
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
94
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Style/DoubleNegation
|
84
95
|
|
85
96
|
def start
|
86
97
|
super
|
@@ -107,7 +118,9 @@ module Fluent
|
|
107
118
|
ssl_client = SslClient.new(
|
108
119
|
host: host, port: port,
|
109
120
|
ca_path: ca_path, ca_file: ca_file,
|
110
|
-
sni: sni,
|
121
|
+
sni: sni, verify_mode: ssl_verify_mode,
|
122
|
+
cert: cert, key: key,
|
123
|
+
timeout: timeout
|
111
124
|
)
|
112
125
|
ssl_client.ssl_info
|
113
126
|
end
|
@@ -121,7 +134,8 @@ module Fluent
|
|
121
134
|
'ssl_version' => ssl_info.ssl_version,
|
122
135
|
'ssl_dn' => ssl_info.subject_s,
|
123
136
|
'ssl_not_after' => ssl_info.not_after,
|
124
|
-
'expire_in_days' => ssl_info.expire_in_days
|
137
|
+
'expire_in_days' => ssl_info.expire_in_days,
|
138
|
+
'serial' => ssl_info.serial
|
125
139
|
}
|
126
140
|
record.update('error_class' => ssl_info.error_class) if ssl_info.error_class
|
127
141
|
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
@@ -141,7 +155,8 @@ module Fluent
|
|
141
155
|
"#{event_prefix}port" => ssl_info.port,
|
142
156
|
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
143
157
|
"#{event_prefix}ssl_version" => ssl_info.ssl_version,
|
144
|
-
"#{event_prefix}ssl_not_after" => ssl_info.not_after
|
158
|
+
"#{event_prefix}ssl_not_after" => ssl_info.not_after,
|
159
|
+
"#{event_prefix}serial" => ssl_info.serial
|
145
160
|
}
|
146
161
|
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
147
162
|
end
|
@@ -155,11 +170,20 @@ module Fluent
|
|
155
170
|
'metric_value' => ssl_info.expire_in_days,
|
156
171
|
"#{event_prefix}host" => ssl_info.host,
|
157
172
|
"#{event_prefix}port" => ssl_info.port,
|
158
|
-
"#{event_prefix}ssl_dn" => ssl_info.subject_s
|
173
|
+
"#{event_prefix}ssl_dn" => ssl_info.subject_s,
|
174
|
+
"#{event_prefix}serial" => ssl_info.serial
|
159
175
|
}
|
160
176
|
router.emit(tag, Fluent::EventTime.from_time(ssl_info.time), record)
|
161
177
|
end
|
162
178
|
|
179
|
+
private
|
180
|
+
|
181
|
+
def ssl_verify_mode
|
182
|
+
return OpenSSL::SSL::VERIFY_PEER if verify_mode == :peer
|
183
|
+
|
184
|
+
OpenSSL::SSL::VERIFY_NONE
|
185
|
+
end
|
186
|
+
|
163
187
|
# ssl info
|
164
188
|
# to encapsulate extracted ssl information
|
165
189
|
class SslInfo
|
@@ -198,6 +222,10 @@ module Fluent
|
|
198
222
|
cert.not_after.iso8601(3)
|
199
223
|
end
|
200
224
|
|
225
|
+
def serial
|
226
|
+
cert&.serial&.to_s(16)&.downcase
|
227
|
+
end
|
228
|
+
|
201
229
|
def status
|
202
230
|
return KO if error
|
203
231
|
|
@@ -214,16 +242,23 @@ module Fluent
|
|
214
242
|
# ssl client
|
215
243
|
# to check ssl status
|
216
244
|
class SslClient
|
217
|
-
attr_reader :host, :port, :ca_path, :ca_file, :sni, :timeout
|
245
|
+
attr_reader :host, :port, :ca_path, :ca_file, :sni, :verify_mode, :cert, :key, :timeout
|
218
246
|
|
219
|
-
|
247
|
+
# rubocop:disable Metrics/ParameterLists
|
248
|
+
def initialize(host:, port:, ca_path: nil, ca_file: nil, sni: true, verify_mode: OpenSSL::SSL::VERIFY_PEER,
|
249
|
+
cert: nil, key: nil,
|
250
|
+
timeout: 5)
|
220
251
|
@host = host
|
221
252
|
@port = port
|
222
253
|
@ca_path = ca_path
|
223
254
|
@ca_file = ca_file
|
224
255
|
@sni = sni
|
256
|
+
@verify_mode = verify_mode
|
257
|
+
@cert = cert
|
258
|
+
@key = key
|
225
259
|
@timeout = timeout
|
226
260
|
end
|
261
|
+
# rubocop:enable Metrics/ParameterLists
|
227
262
|
|
228
263
|
def ssl_info
|
229
264
|
info = SslInfo.new(host: host, port: port)
|
@@ -257,10 +292,12 @@ module Fluent
|
|
257
292
|
|
258
293
|
def ssl_context
|
259
294
|
OpenSSL::SSL::SSLContext.new.tap do |ssl_context|
|
260
|
-
ssl_context.verify_mode =
|
295
|
+
ssl_context.verify_mode = verify_mode
|
261
296
|
ssl_context.cert_store = store
|
262
297
|
ssl_context.min_version = nil
|
263
298
|
ssl_context.max_version = OpenSSL::SSL::TLS1_2_VERSION
|
299
|
+
ssl_context.cert = OpenSSL::X509::Certificate.new(File.open(cert)) if cert
|
300
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(File.open(key)) if key
|
264
301
|
end
|
265
302
|
end
|
266
303
|
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.3.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: 2023-
|
11
|
+
date: 2023-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bump
|