fluent-plugin-ssl-check 2.1.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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