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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd66e101f055ca5f4cf4d6ab29d548cb73df7783c9429171f03a397aaddd856f
4
- data.tar.gz: 69fd54b23c4a88fa90565cf6bcb8d73990e96e0f42f869fd3fabf1ca16fa5f72
3
+ metadata.gz: ab7b3def2e942f92cf1b8a1fa46f4c7bafe50fbee692334736e19574849e9911
4
+ data.tar.gz: 5083966b749ba1407cdce60b33f8952dce4b300c5bd7e33496e1b1e02ae0814a
5
5
  SHA512:
6
- metadata.gz: 04500e488c04750d2f480037aa80feb16baf8d7a23b9b01f1921bbe201510b3b35a5694703da018a43705786af6d95ce67d7ee40fc0e661cd1df42823b640e4f
7
- data.tar.gz: 13da4ca2dd02dd8c9a983570097cfa30b12b0f7e9dd0f573762d440c366fe0e0afc9b67deebf8c735dc87eaf52d8b1915dc3728b3179aa4d3686c5cc9a64c652
6
+ metadata.gz: fe0d1bd834d8831a510df5754cb488d2e543fbca465bf3b344312b92f236278fbd75cf972efee0d0ffc45838f4550d09f81dba34fbcbf0445810a831b6fda365
7
+ data.tar.gz: 8cef76bf6831eae2d1053a99699fc07f31077939bd3bc5ab28a402be4d709f9f4eec53ec9c14e954a01cefd5866a399e4d2ceeb373bd0e94d205023bf0375b3a
data/.rubocop.yml CHANGED
@@ -26,9 +26,6 @@ Metrics/ClassLength:
26
26
  Metrics/MethodLength:
27
27
  Max: 20
28
28
 
29
- Metrics/ParameterLists:
30
- Max: 6
31
-
32
29
  # Naming/MethodParameterName:
33
30
  # Exclude:
34
31
  # - lib/fluent/plugin/in_ssl_check.rb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-ssl-check (2.1.0)
4
+ fluent-plugin-ssl-check (2.3.0)
5
5
  fluentd (>= 0.14.10, < 2)
6
6
 
7
7
  GEM
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:
@@ -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.1.0'
8
+ spec.version = '2.3.0'
9
9
  spec.authors = ['Thomas Tych']
10
10
  spec.email = ['thomas.tych@gmail.com']
11
11
 
@@ -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.' if !hosts || hosts.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, timeout: timeout
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
- def initialize(host:, port:, ca_path: nil, ca_file: nil, sni: true, timeout: 5)
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 = OpenSSL::SSL::VERIFY_PEER
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.1.0
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-09-12 00:00:00.000000000 Z
11
+ date: 2023-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bump