sensu-plugins-ssl 1.4.0 → 3.0.2

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
- SHA1:
3
- metadata.gz: 4bb08666a55b083ef5b2e8c252152420e943da99
4
- data.tar.gz: c32e3f6fd49c1436073833748c619c571f7d0947
2
+ SHA256:
3
+ metadata.gz: 61a03c614854b22a64ca82592d13705f04a51b4dc564f8659ed0e8ce46eacd9e
4
+ data.tar.gz: 4f15129501ac3878eef485918941e74455eaa9c6245d60f0a2980f70c502785a
5
5
  SHA512:
6
- metadata.gz: 7999f8f52dd451240c33c68c3f8d5ed1b9c2e7fe6777b7462cde2d3aedf7f290121c2761233a48e67205929b26a1a5a25fa2dbde8b0b5e34338059bf78dca699
7
- data.tar.gz: f1e7d24517dcae4ab6ad0098e951a9bed7ab8cdfab4b71f90db73c4c0965595bc3016161a962bc5e865a1736cffb60d45191eed9b06354bf5dbd4b6f6901e311
6
+ metadata.gz: 0ee7fbca09b4a980e1b027b1c59f9bdac98e3a1e4c0ecf7f031aa18a0cb14f068e267cfe4031f05b7ec6b3837cdae5512ff24df1a2aa080ad2261ee50762144b
7
+ data.tar.gz: 89d0f6aa80d3ee579f2204382726a40838bcd1b72163f020a093c9c27993c8d54794d0a3dfb01f19d625429b7fc17e9f6df2b8aa7ca2e8f907e23ea9b26cd758
@@ -1,10 +1,69 @@
1
1
  # Change Log
2
2
  This project adheres to [Semantic Versioning](http://semver.org/).
3
3
 
4
- This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachangelog.com/)
4
+ This CHANGELOG follows the format listed [here](https://github.com/sensu-plugins/community/blob/master/HOW_WE_CHANGELOG.md).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [3.0.1] - 2020-08-27
9
+ ### Changed
10
+ - Fixed bonsai script in .travis.yml
11
+
12
+ ## [3.0.1] - 2020-08-27
13
+ ### Changed
14
+ - Modified .travis.yml to re-order deploy steps
15
+
16
+ ## [3.0.0] - 2020-08-27
17
+ ### Breaking Changes
18
+ - Bump `sensu-plugin` dependency from `~> 1.2` to `~> 4.0` you can read the changelog entries for [4.0](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#400---2018-02-17), [3.0](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#300---2018-12-04), and [2.0](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#v200---2017-03-29)
19
+ - Remove ruby-2.3.0. Upgrade bundler. Fix failing tests (@phumpal).
20
+
21
+ ### Added
22
+ - Travis build automation to generate Sensu Asset tarballs that can be used n conjunction with Sensu provided ruby runtime assets and the Bonsai Asset Index
23
+ - Require latest sensu-plugin for [Sensu Go support](https://github.com/sensu-plugins/sensu-plugin#sensu-go-enablement)
24
+ - New option to treat anchor argument as a regexp
25
+ - New Check plugin `check-ssl-root-issuer.rb` with alternative logic for trust anchor verification.
26
+
27
+ ### Changed
28
+ - `check-ssl-anchor.rb` uses regexp to test for present of certificates in cert chain that works with both openssl 1.0 and 1.1 formatting
29
+ - Upgrade rake and rubocop dependencies
30
+ - Remediate rubocop issues
31
+
32
+ ### Fixed
33
+ - ssl-anchor test now uses regexp
34
+
35
+ ## [2.0.1] - 2018-05-30
36
+ ### Fixed
37
+ - `check-ssl-qualys.rb`: Fixed typo and removed timeout `-t` short option replacing it with `--timeout` as per previous changelog. `-t` conflicts with the short option for `--time-between`
38
+ - Fixed typo in changelog
39
+
40
+ ## [2.0.0] - 2018-03-27
41
+ ### Breaking Changes
42
+ - `check-ssl-qualys.rb`: when you submit a request with caching enabled it will return back a response including an eta key. Rather than sleeping for some arbitrary number of time we now use this key when its greater than `--time-between` to wait before attempting the next attempt to query. If it is lower or not present we fall back to `--time-between` (@majormoses)
43
+ - `check-ssl-qualys.rb`: new `--timeout` parameter to short circuit slow apis (@majormoses)
44
+
45
+ ### Changed
46
+ - `check-ssl-qualys.rb`: updated `--api-url` to default to `v3` but remains backwards compatible (@jhoblitt) (@majormoses)
47
+
48
+ ### Added
49
+ `check-ssl-qualys.rb`: option `--debug` to enable debug logging (@majormoses)
50
+
51
+ ### Fixed
52
+ - `check-ssl-hsts-preloadable.rb`: Fixed testing warnings for if a domain can be HSTS preloaded (@rwky)
53
+
54
+ ## [1.5.0] - 2017-09-26
55
+ ### Added
56
+ - Ruby 2.4.1 testing
57
+ - `check-ssl-hsts-preload.rb`: Added check for testing preload status of HSTS (@rwky)
58
+ - `check-ssl-hsts-preloadable.rb`: Added check for testing if a domain can be HSTS preloaded (@rwky)
59
+
60
+ ### Changed
61
+ - updated CHANGELOG guidelines location (@majormoses)
62
+
63
+ ### Fixed
64
+ - `check-java-keystore-cert.rb`: Export cert in PEM format to fix tests that broke going from Precise to Trusty travis workers (@eheydrick)
65
+ - fixed spelling in github pr template (@majormoses)
66
+
8
67
  ## [1.4.0] - 2017-06-20
9
68
  ### Added
10
69
  - `check-ssl-anchor.rb`: Add check for a specific root certificate signature. (@pgporada)
@@ -78,7 +137,13 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
78
137
  ### Added
79
138
  - initial release
80
139
 
81
- [Unreleased]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.4.0...HEAD
140
+ [Unreleased]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/3.0.2...HEAD
141
+ [3.0.2]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/3.0.1...3.0.2
142
+ [3.0.1]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/3.0.0...3.0.1
143
+ [3.0.0]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/2.0.1...3.0.0
144
+ [2.0.1]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/2.0.0...2.0.1
145
+ [2.0.0]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.5.0...2.0.0
146
+ [1.5.0]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.4.0...1.5.0
82
147
  [1.4.0]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.3.1...1.4.0
83
148
  [1.3.1]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.3.0...1.3.1
84
149
  [1.3.0]: https://github.com/sensu-plugins/sensu-plugins-ssl/compare/1.2.0...1.3.0
data/README.md CHANGED
@@ -5,7 +5,10 @@
5
5
  [![Code Climate](https://codeclimate.com/github/sensu-plugins/sensu-plugins-ssl/badges/gpa.svg)](https://codeclimate.com/github/sensu-plugins/sensu-plugins-ssl)
6
6
  [![Test Coverage](https://codeclimate.com/github/sensu-plugins/sensu-plugins-ssl/badges/coverage.svg)](https://codeclimate.com/github/sensu-plugins/sensu-plugins-ssl)
7
7
  [![Dependency Status](https://gemnasium.com/sensu-plugins/sensu-plugins-ssl.svg)](https://gemnasium.com/sensu-plugins/sensu-plugins-ssl)
8
+ [![Sensu Bonsai Asset](https://img.shields.io/badge/Bonsai-Download%20Me-brightgreen.svg?colorB=89C967&logo=sensu)](https://bonsai.sensu.io/assets/sensu-plugins/sensu-plugins-ssl)
8
9
 
10
+ ## Sensu Asset
11
+ The Sensu assets packaged from this repository are built against the Sensu Ruby runtime environment. When using these assets as part of a Sensu Go resource (check, mutator or handler), make sure you include the corresponding Sensu Ruby runtime asset in the list of assets needed by the resource. The current ruby-runtime assets can be found [here](https://bonsai.sensu.io/assets/sensu/sensu-ruby-runtime) in the [Bonsai Asset Index](bonsai.sensu.io).
9
12
  ## Functionality
10
13
 
11
14
  ## Files
@@ -14,13 +17,16 @@
14
17
  * bin/check-ssl-crl.rb
15
18
  * bin/check-ssl-cert.rb
16
19
  * bin/check-ssl-host.rb
20
+ * bin/check-ssl-hsts-preload.rb
21
+ * bin/check-ssl-hsts-preloadable.rb
17
22
  * bin/check-ssl-qualys.rb
23
+ * bin/check-ssl-root-issuer.rb
18
24
 
19
25
  ## Usage
20
26
 
21
27
  ### `bin/check-ssl-anchor.rb`
22
28
 
23
- Check that a specific website is chained to a specific root certificate (Let's Encrypt for instance).
29
+ Check that a specific website is chained to a specific root certificate (Let's Encrypt for instance). Requires the `openssl` commandline tool to be available on the system.
24
30
 
25
31
  ```
26
32
  ./bin/check-ssl-anchor.rb -u example.com -a "i:/O=Digital Signature Trust Co./CN=DST Root CA X3"
@@ -44,6 +50,21 @@ or an online CRL:
44
50
 
45
51
  Critical and Warning thresholds are specified in minutes.
46
52
 
53
+ ### `bin/check-ssl-qualys.rb`
54
+
55
+ Checks the ssllabs qualysis api for grade of your server, this check can be quite long so it should not be scheduled with a low interval and will probably need to adjust the check `timeout` options per the [check attributes spec](https://docs.sensu.io/sensu-core/1.2/reference/checks/#check-attributes) based on my tests you should expect this to take around 3 minutes.
56
+ ```
57
+ ./bin/check-ssl-qualys.rb -d google.com
58
+ ```
59
+
60
+ ### `bin/check-ssl-root-issuer.rb`
61
+
62
+ Check that a specific website is chained to a specific root certificate issuer. This is a pure Ruby implementation, does not require the openssl cmdline client tool to be installed.
63
+
64
+ ```
65
+ ./bin/check-ssl-root-issuer.rb -u example.com -a "CN=DST Root CA X3,O=Digital Signature Trust Co."
66
+ ```
67
+
47
68
  ## Installation
48
69
 
49
70
  [Installation and Setup](http://sensu-plugins.io/docs/installation_instructions.html)
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
2
4
  #
3
5
  # check-java-keystore-cert
4
6
  #
@@ -56,8 +58,8 @@ class CheckJavaKeystoreCert < Sensu::Plugin::Check::CLI
56
58
  def certificate_expiration_date
57
59
  result = `keytool -keystore #{Shellwords.escape(config[:path])} \
58
60
  -export -alias #{Shellwords.escape(config[:alias])} \
59
- -storepass #{Shellwords.escape(config[:password])} 2>&1 | \
60
- openssl x509 -enddate -inform der -noout 2>&1`
61
+ -storepass #{Shellwords.escape(config[:password])} -rfc 2>&1 | \
62
+ openssl x509 -enddate -noout 2>&1`
61
63
 
62
64
  # rubocop:disable Style/SpecialGlobalVars
63
65
  unknown 'could not get certificate from keystore' unless $?.success?
@@ -75,7 +77,7 @@ class CheckJavaKeystoreCert < Sensu::Plugin::Check::CLI
75
77
 
76
78
  days_until = (certificate_expiration_date - Date.today).to_i
77
79
 
78
- if days_until < 0
80
+ if days_until < 0 # rubocop: disable Style/NumericPredicate
79
81
  critical "Expired #{days_until.abs} days ago"
80
82
  elsif days_until < config[:critical]
81
83
  critical "#{days_until} days left"
@@ -1,4 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
2
4
  #
3
5
  # check-ssl-anchor
4
6
  #
@@ -57,6 +59,14 @@ class CheckSSLAnchor < Sensu::Plugin::Check::CLI
57
59
  long: '--anchor ANCHOR_VAL',
58
60
  required: true
59
61
 
62
+ option :regexp,
63
+ description: 'Treat the anchor as a regexp',
64
+ short: '-r',
65
+ long: '--regexp',
66
+ default: false,
67
+ boolean: true,
68
+ required: false
69
+
60
70
  option :servername,
61
71
  description: 'Set the TLS SNI (Server Name Indication) extension',
62
72
  short: '-s',
@@ -79,7 +89,7 @@ class CheckSSLAnchor < Sensu::Plugin::Check::CLI
79
89
  -servername #{config[:servername]} < /dev/null 2>&1`.match(/Certificate chain(.*)---\nServer certificate/m)[1].split(/$/).map(&:strip)
80
90
  data = data.reject(&:empty?)
81
91
 
82
- unless data[0] =~ /0 s:\/CN=.*/m
92
+ unless data[0] =~ /0 s:\/?CN ?=.*/m
83
93
  data = 'NOTOK'
84
94
  end
85
95
  data
@@ -91,11 +101,22 @@ class CheckSSLAnchor < Sensu::Plugin::Check::CLI
91
101
  if data == 'NOTOK'
92
102
  critical 'An error was encountered while trying to retrieve the certificate chain.'
93
103
  end
94
-
95
- if data[-1] == config[:anchor].to_s
96
- ok 'Root anchor has been found.'
104
+ puts config[:regexp]
105
+ # rubocop:disable Style/IfInsideElse
106
+ if config[:regexp]
107
+ anchor_regexp = Regexp.new(config[:anchor].to_s)
108
+ if data[-1] =~ anchor_regexp
109
+ ok 'Root anchor has been found.'
110
+ else
111
+ critical 'Root anchor did not match regexp /' + config[:anchor].to_s + "/\nFound \"" + data[-1] + '" instead.'
112
+ end
97
113
  else
98
- critical 'Root anchor did not match. Found "' + data[-1] + '" instead.'
114
+ if data[-1] == config[:anchor].to_s
115
+ ok 'Root anchor has been found.'
116
+ else
117
+ critical 'Root anchor did not match string "' + config[:anchor].to_s + "\"\nFound \"" + data[-1] + '" instead.'
118
+ end
99
119
  end
120
+ # rubocop:enable Style/IfInsideElse
100
121
  end
101
122
  end
@@ -1,4 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
2
4
  #
3
5
  # check-ssl-cert
4
6
  #
@@ -117,7 +119,7 @@ class CheckSSLCert < Sensu::Plugin::Check::CLI
117
119
 
118
120
  days_until = (Date.parse(expiry.to_s) - Date.today).to_i
119
121
 
120
- if days_until < 0
122
+ if days_until < 0 # rubocop:disable Style/NumericPredicate
121
123
  critical "Expired #{days_until.abs} days ago"
122
124
  elsif days_until < config[:critical].to_i
123
125
  critical "#{days_until} days left"
@@ -1,4 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
2
4
  #
3
5
  # check-ssl-crl
4
6
  #
@@ -65,10 +67,10 @@ class CheckSSLCRL < Sensu::Plugin::Check::CLI
65
67
  def run
66
68
  validate_opts
67
69
 
68
- next_update = OpenSSL::X509::CRL.new(open(config[:url]).read).next_update
70
+ next_update = OpenSSL::X509::CRL.new(open(config[:url]).read).next_update # rubocop:disable Security/Open
69
71
  minutes_until = seconds_to_minutes(Time.parse(next_update.to_s) - Time.now)
70
72
 
71
- critical "#{config[:url]} - Expired #{minutes_until.abs} minutes ago" if minutes_until < 0
73
+ critical "#{config[:url]} - Expired #{minutes_until.abs} minutes ago" if minutes_until < 0 # rubocop:disable Style/NumericPredicate
72
74
  critical "#{config[:url]} - #{minutes_until} minutes left, next update at #{next_update}" if minutes_until < config[:critical].to_i
73
75
  warning "#{config[:url]} - #{minutes_until} minutes left, next update at #{next_update}" if minutes_until < config[:warning].to_i
74
76
  ok "#{config[:url]} - #{minutes_until} minutes left, next update at #{next_update}"
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: UTF-8
2
+ # frozen_string_literal: false
3
+
3
4
  # check-ssl-host.rb
4
5
  #
5
6
  # DESCRIPTION:
@@ -42,7 +43,7 @@ require 'socket'
42
43
  # Check SSL Host
43
44
  #
44
45
  class CheckSSLHost < Sensu::Plugin::Check::CLI
45
- STARTTLS_PROTOS = %w(smtp imap).freeze
46
+ STARTTLS_PROTOS = %w[smtp imap].freeze
46
47
 
47
48
  check_name 'check_ssl_host'
48
49
 
@@ -104,7 +105,7 @@ class CheckSSLHost < Sensu::Plugin::Check::CLI
104
105
  long: '--starttls PROTO'
105
106
 
106
107
  def get_cert_chain(host, port, address, client_cert, client_key)
107
- tcp_client = TCPSocket.new(address ? address : host, port)
108
+ tcp_client = TCPSocket.new(address ? address : host, port) # rubocop:disable Style/RedundantCondition
108
109
  handle_starttls(config[:starttls], tcp_client) if config[:starttls]
109
110
  ssl_context = OpenSSL::SSL::SSLContext.new
110
111
  ssl_context.cert = OpenSSL::X509::Certificate.new File.read(client_cert) if client_cert
@@ -139,6 +140,7 @@ class CheckSSLHost < Sensu::Plugin::Check::CLI
139
140
 
140
141
  status = socket.readline
141
142
  return if /^220 / =~ status
143
+
142
144
  critical "#{config[:host]} - did not receive SMTP 220 in response to STARTTLS"
143
145
  end
144
146
 
@@ -151,6 +153,7 @@ class CheckSSLHost < Sensu::Plugin::Check::CLI
151
153
 
152
154
  status = socket.readline
153
155
  return if /^a001 OK Begin TLS negotiation now/ =~ status
156
+
154
157
  critical "#{config[:host]} - did not receive OK Begin TLS negotiation now"
155
158
  end
156
159
 
@@ -158,7 +161,7 @@ class CheckSSLHost < Sensu::Plugin::Check::CLI
158
161
  # Expiry check
159
162
  days = (cert.not_after.to_date - Date.today).to_i
160
163
  message = "#{config[:host]} - #{days} days until expiry"
161
- critical "#{config[:host]} - Expired #{days} days ago" if days < 0
164
+ critical "#{config[:host]} - Expired #{days} days ago" if days < 0 # rubocop:disable Style/NumericPredicate
162
165
  critical message if days < config[:critical]
163
166
  warning message if days < config[:warning]
164
167
  ok message
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
4
+ # check-ssl-hsts-preloadable.rb
5
+ #
6
+ # DESCRIPTION:
7
+ # Checks a domain against the chromium HSTS API returning errors/warnings if the domain is preloadable
8
+ #
9
+ # OUTPUT:
10
+ # plain text
11
+ #
12
+ # PLATFORMS:
13
+ # Linux
14
+ #
15
+ # DEPENDENCIES:
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # # Basic usage
20
+ # check-ssl-hsts-preloadable.rb -d <domain_name>
21
+ #
22
+ # LICENSE:
23
+ # Copyright 2017 Rowan Wookey <admin@rwky.net>
24
+ # Released under the same terms as Sensu (the MIT license); see LICENSE for
25
+ # details.
26
+ #
27
+ # Inspired by https://github.com/sensu-plugins/sensu-plugins-ssl/blob/master/bin/check-ssl-qualys.rb Copyright 2015 William Cooke <will@bruisyard.eu>
28
+ #
29
+
30
+ require 'sensu-plugin/check/cli'
31
+ require 'json'
32
+ require 'net/http'
33
+
34
+ class CheckSSLHSTSPreloadable < Sensu::Plugin::Check::CLI
35
+ option :domain,
36
+ description: 'The domain to run the test against',
37
+ short: '-d DOMAIN',
38
+ long: '--domain DOMAIN',
39
+ required: true
40
+
41
+ option :api_url,
42
+ description: 'The URL of the API to run against',
43
+ long: '--api-url URL',
44
+ default: 'https://hstspreload.org/api/v2/preloadable'
45
+
46
+ def fetch(uri, limit = 10)
47
+ if limit == 0 # rubocop:disable Style/NumericPredicate
48
+ return nil
49
+ end
50
+
51
+ response = Net::HTTP.get_response(uri)
52
+
53
+ case response
54
+ when Net::HTTPSuccess
55
+ response
56
+ when Net::HTTPRedirection
57
+ location = URI(response['location'])
58
+ fetch(location, limit - 1)
59
+ end
60
+ end
61
+
62
+ def run
63
+ uri = URI(config[:api_url])
64
+ uri.query = URI.encode_www_form(domain: config[:domain])
65
+ response = fetch(uri)
66
+ if response.nil?
67
+ return warning 'Bad response recieved from API'
68
+ end
69
+
70
+ body = JSON.parse(response.body)
71
+ if !body['errors'].empty?
72
+ critical body['errors'].map { |u| u['summary'] }.join(', ')
73
+ elsif !body['warnings'].empty?
74
+ warning body['warnings'].map { |u| u['summary'] }.join(', ')
75
+ else
76
+ ok
77
+ end
78
+ end
79
+ end
80
+
81
+ # vim: set tabstop=2 shiftwidth=2 expandtab:
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
4
+ # check-ssl-hsts-preload.rb
5
+ #
6
+ # DESCRIPTION:
7
+ # Checks a domain against the chromium HSTS API reporting on the preload status of the domain
8
+ #
9
+ # OUTPUT:
10
+ # plain text
11
+ #
12
+ # PLATFORMS:
13
+ # Linux
14
+ #
15
+ # DEPENDENCIES:
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # # Basic usage
20
+ # check-ssl-hsts-preload.rb -d <domain_name>
21
+ # # Specify the CRITICAL and WARNING alerts to either unknown (not in the database), pending or preloaded
22
+ # check-ssl-hsts-preload.rb -d <domain_name> -c <critical_alert> -w <warning_alert>
23
+ #
24
+ # LICENSE:
25
+ # Copyright 2017 Rowan Wookey <admin@rwky.net>
26
+ # Released under the same terms as Sensu (the MIT license); see LICENSE for
27
+ # details.
28
+ #
29
+ # Inspired by https://github.com/sensu-plugins/sensu-plugins-ssl/blob/master/bin/check-ssl-qualys.rb Copyright 2015 William Cooke <will@bruisyard.eu>
30
+ #
31
+
32
+ require 'sensu-plugin/check/cli'
33
+ require 'json'
34
+ require 'net/http'
35
+
36
+ class CheckSSLHSTSStatus < Sensu::Plugin::Check::CLI
37
+ STATUSES = %w[unknown pending preloaded].freeze
38
+
39
+ option :domain,
40
+ description: 'The domain to run the test against',
41
+ short: '-d DOMAIN',
42
+ long: '--domain DOMAIN',
43
+ required: true
44
+
45
+ option :warn,
46
+ short: '-w STATUS',
47
+ long: '--warn STATUS',
48
+ description: 'WARNING if this status or worse',
49
+ in: STATUSES,
50
+ default: 'pending'
51
+
52
+ option :critical,
53
+ short: '-c STATUS',
54
+ long: '--critical STATUS',
55
+ description: 'CRITICAL if this status or worse',
56
+ in: STATUSES,
57
+ default: 'unknown'
58
+
59
+ option :api_url,
60
+ description: 'The URL of the API to run against',
61
+ long: '--api-url URL',
62
+ default: 'https://hstspreload.org/api/v2/status'
63
+
64
+ def fetch(uri, limit = 10)
65
+ if limit == 0 # rubocop:disable Style/NumericPredicate
66
+ return nil
67
+ end
68
+
69
+ response = Net::HTTP.get_response(uri)
70
+
71
+ case response
72
+ when Net::HTTPSuccess
73
+ response
74
+ when Net::HTTPRedirection
75
+ location = URI(response['location'])
76
+ fetch(location, limit - 1)
77
+ end
78
+ end
79
+
80
+ def run
81
+ uri = URI(config[:api_url])
82
+ uri.query = URI.encode_www_form(domain: config[:domain])
83
+ response = fetch(uri)
84
+ if response.nil?
85
+ return warning 'Bad response recieved from API'
86
+ end
87
+
88
+ body = JSON.parse(response.body)
89
+ unless STATUSES.include? body['status']
90
+ warning 'Invalid status returned ' + body['status']
91
+ end
92
+
93
+ if STATUSES.index(body['status']) <= STATUSES.index(config[:critical])
94
+ critical body['status']
95
+ elsif STATUSES.index(body['status']) <= STATUSES.index(config[:warn])
96
+ warning body['status']
97
+ else
98
+ ok
99
+ end
100
+ end
101
+ end
102
+
103
+ # vim: set tabstop=2 shiftwidth=2 expandtab:
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- # encoding: UTF-8
2
+ # frozen_string_literal: false
3
+
3
4
  # check-ssl-qualys.rb
4
5
  #
5
6
  # DESCRIPTION:
@@ -41,6 +42,7 @@
41
42
  require 'sensu-plugin/check/cli'
42
43
  require 'json'
43
44
  require 'net/http'
45
+ require 'timeout'
44
46
 
45
47
  # Checks a single DNS entry has a rating above a certain level
46
48
  class CheckSSLQualys < Sensu::Plugin::Check::CLI
@@ -56,7 +58,7 @@ class CheckSSLQualys < Sensu::Plugin::Check::CLI
56
58
  option :api_url,
57
59
  description: 'The URL of the API to run against',
58
60
  long: '--api-url URL',
59
- default: 'https://api.ssllabs.com/api/v2/'
61
+ default: 'https://api.ssllabs.com/api/v3/'
60
62
 
61
63
  option :warn,
62
64
  short: '-w GRADE',
@@ -72,6 +74,12 @@ class CheckSSLQualys < Sensu::Plugin::Check::CLI
72
74
  proc: proc { |g| GRADE_OPTIONS.index(g) },
73
75
  default: 3 # 'B'
74
76
 
77
+ option :debug,
78
+ long: '--debug BOOL',
79
+ description: 'toggles extra debug printing',
80
+ boolean: true,
81
+ default: false
82
+
75
83
  option :num_checks,
76
84
  short: '-n NUM_CHECKS',
77
85
  long: '--number-checks NUM_CHECKS',
@@ -82,17 +90,31 @@ class CheckSSLQualys < Sensu::Plugin::Check::CLI
82
90
  option :between_checks,
83
91
  short: '-t SECONDS',
84
92
  long: '--time-between SECONDS',
85
- description: 'The time between each poll of the API',
93
+ description: 'The fallback time between each poll of the API, when an ETA is given by the previous response and is higher than this value it is used',
86
94
  proc: proc { |t| t.to_i },
87
95
  default: 10
88
96
 
97
+ option :timeout,
98
+ long: '--timeout SECONDS',
99
+ descriptions: 'the amount of seconds that this is allowed to run for',
100
+ proc: proc(&:to_i),
101
+ default: 300
102
+
89
103
  def ssl_api_request(from_cache)
90
104
  params = { host: config[:domain] }
91
- params[:startNew] = 'on' unless from_cache
105
+ params[:startNew] = if from_cache == true
106
+ 'off'
107
+ else
108
+ 'on'
109
+ end
92
110
 
93
111
  uri = URI("#{config[:api_url]}analyze")
94
112
  uri.query = URI.encode_www_form(params)
95
- response = Net::HTTP.get_response(uri)
113
+ begin
114
+ response = Net::HTTP.get_response(uri)
115
+ rescue StandardError => e
116
+ warning e
117
+ end
96
118
 
97
119
  warning 'Bad response recieved from API' unless response.is_a?(Net::HTTPSuccess)
98
120
 
@@ -107,11 +129,38 @@ class CheckSSLQualys < Sensu::Plugin::Check::CLI
107
129
 
108
130
  def ssl_recheck
109
131
  1.upto(config[:num_checks]) do |step|
110
- json = ssl_check(step != 1)
132
+ p "step: #{step}" if config[:debug]
133
+ start_time = Time.now
134
+ p "start_time: #{start_time}" if config[:debug]
135
+ json = if step == 1
136
+ ssl_check(false)
137
+ else
138
+ ssl_check(true)
139
+ end
111
140
  return json if json['status'] == 'READY'
112
- sleep(config[:between_checks])
141
+
142
+ if json['endpoints'] && json['endpoints'].is_a?(Array) # rubocop:disable Style/SafeNavigation
143
+ p "endpoints: #{json['endpoints']}" if config[:debug]
144
+ # The api response sometimes has low eta (which seems unrealistic) from
145
+ # my tests that can be 0 or low numbers which would imply it is done...
146
+ # Basically we check if present and if its higher than the specified
147
+ # time to wait between checks. If so we use the eta from the api get
148
+ # response otherwise we use the time between check values. We have an
149
+ # overall timeout that protects us from the api telling us to wait for
150
+ # insanely long time periods. The highest I have seen the eta go was
151
+ # around 250 seconds but put it in just in case as the api has very
152
+ # erratic response times.
153
+ if json['endpoints'].first.is_a?(Hash) && json['endpoints'].first.key?('eta') && json['endpoints'].first['eta'] > config[:between_checks]
154
+ p "eta: #{json['endpoints'].first['eta']}" if config[:debug]
155
+ sleep(json['endpoints'].first['eta'])
156
+ else
157
+ p "sleeping with default: #{config[:between_checks]}" if config[:debug]
158
+ sleep(config[:between_checks])
159
+ end
160
+ end
161
+ p "elapsed: #{Time.now - start_time}" if config[:debug]
162
+ warning 'Timeout waiting for check to finish' if step == config[:num_checks]
113
163
  end
114
- warning 'Timeout waiting for check to finish'
115
164
  end
116
165
 
117
166
  def ssl_grades
@@ -121,23 +170,25 @@ class CheckSSLQualys < Sensu::Plugin::Check::CLI
121
170
  end
122
171
 
123
172
  def lowest_grade
124
- ssl_grades.sort_by! { |g| GRADE_OPTIONS.index(g) } .reverse![0]
173
+ ssl_grades.sort_by! { |g| GRADE_OPTIONS.index(g) }.reverse![0]
125
174
  end
126
175
 
127
176
  def run
128
- grade = lowest_grade
129
- unless grade
130
- message "#{config[:domain]} not rated"
131
- critical
132
- end
133
- message "#{config[:domain]} rated #{grade}"
134
- grade_rank = GRADE_OPTIONS.index(grade)
135
- if grade_rank > config[:critical]
136
- critical
137
- elsif grade_rank > config[:warn]
138
- warning
139
- else
140
- ok
177
+ Timeout.timeout(config[:timeout]) do
178
+ grade = lowest_grade
179
+ unless grade
180
+ message "#{config[:domain]} not rated"
181
+ critical
182
+ end
183
+ message "#{config[:domain]} rated #{grade}"
184
+ grade_rank = GRADE_OPTIONS.index(grade)
185
+ if grade_rank > config[:critical]
186
+ critical
187
+ elsif grade_rank > config[:warn]
188
+ warning
189
+ else
190
+ ok
191
+ end
141
192
  end
142
193
  end
143
194
  end
@@ -0,0 +1,128 @@
1
+ #! /usr/bin/env ruby
2
+ # frozen_string_literal: false
3
+
4
+ #
5
+ # check-ssl-root-issuer
6
+ #
7
+ # DESCRIPTION:
8
+ # Check that a certificate is chained to a specific root certificate issuer
9
+ #
10
+ # OUTPUT:
11
+ # plain text
12
+ #
13
+ # PLATFORMS:
14
+ # Linux
15
+ #
16
+ # DEPENDENCIES:
17
+ # gem: sensu-plugin
18
+ #
19
+ # USAGE:
20
+ #
21
+ # Check that a specific website is chained to a specific root certificate
22
+ # ./check-ssl-root-issuer.rb \
23
+ # -u https://example.com \
24
+ # -i "CN=DST Root CA X3,O=Digital Signature Trust Co."
25
+ #
26
+ # LICENSE:
27
+ # Copyright Jef Spaleta (jspaleta@gmail.com) 2020
28
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
29
+ # for details.
30
+ #
31
+
32
+ require 'sensu-plugin/check/cli'
33
+ require 'openssl'
34
+ require 'uri'
35
+ require 'net/http'
36
+ require 'net/https'
37
+
38
+ #
39
+ # Check root certificate has specified issuer name
40
+ #
41
+ class CheckSSLRootIssuer < Sensu::Plugin::Check::CLI
42
+ option :url,
43
+ description: 'Url to check: Ex "https://google.com"',
44
+ short: '-u',
45
+ long: '--url URL',
46
+ required: true
47
+
48
+ option :issuer,
49
+ description: 'An X509 certificate issuer name, RFC2253 format Ex: "CN=DST Root CA X3,O=Digital Signature Trust Co."',
50
+ short: '-i',
51
+ long: '--issuer ISSUER_NAME',
52
+ required: true
53
+
54
+ option :regexp,
55
+ description: 'Treat the issuer name as a regexp',
56
+ short: '-r',
57
+ long: '--regexp',
58
+ default: false,
59
+ boolean: true,
60
+ required: false
61
+
62
+ option :format,
63
+ description: 'optional issuer name format.',
64
+ short: '-f',
65
+ long: '--format FORMAT_VAL',
66
+ default: 'RFC2253',
67
+ in: %w[RFC2253 ONELINE COMPAT],
68
+ required: false
69
+
70
+ def cert_name_format
71
+ # Note: because format argument is pre-validated by mixin 'in' logic eval is safe to use
72
+ eval "OpenSSL::X509::Name::#{config[:format]}" # rubocop:disable Security/Eval, Style/EvalWithLocation
73
+ end
74
+
75
+ def validate_issuer(cert)
76
+ issuer = cert.issuer.to_s(cert_name_format)
77
+ if config[:regexp]
78
+ issuer_regexp = Regexp.new(config[:issuer].to_s)
79
+ issuer =~ issuer_regexp
80
+ else
81
+ issuer == config[:issuer].to_s
82
+ end
83
+ end
84
+
85
+ def find_root_cert(uri)
86
+ root_cert = nil
87
+ http = Net::HTTP.new(uri.host, uri.port)
88
+ http.open_timeout = 10
89
+ http.read_timeout = 10
90
+ http.use_ssl = true
91
+ http.cert_store = OpenSSL::X509::Store.new
92
+ http.cert_store.set_default_paths
93
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
94
+
95
+ http.verify_callback = lambda { |verify_ok, store_context|
96
+ root_cert = store_context.current_cert unless root_cert # rubocop:disable Style/OrAssignment
97
+ unless verify_ok
98
+ @failed_cert = store_context.current_cert
99
+ @failed_cert_reason = [store_context.error, store_context.error_string] if store_context.error != 0
100
+ end
101
+ verify_ok
102
+ }
103
+ http.start {}
104
+ root_cert
105
+ end
106
+
107
+ # Do the actual work and massage some data
108
+
109
+ def run
110
+ @fail_cert = nil
111
+ @failed_cert_reason = 'Unknown'
112
+ uri = URI.parse(config[:url])
113
+ critical "url protocol must be https, you specified #{url}" if uri.scheme != 'https'
114
+ root_cert = find_root_cert(uri)
115
+ if @failed_cert
116
+ msg = "Certificate verification failed.\n Reason: #{@failed_cert_reason}"
117
+ critical msg
118
+ end
119
+
120
+ if validate_issuer(root_cert)
121
+ msg = 'Root certificate in chain has expected issuer name'
122
+ ok msg
123
+ else
124
+ msg = "Root certificate issuer did not match expected name.\nFound: \"#{root_cert.issuer.to_s(config[:issuer_format])}\""
125
+ critical msg
126
+ end
127
+ end
128
+ end
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sensu-plugins-ssl/version'
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SensuPluginsSSL
2
4
  module Version
3
- MAJOR = 1
4
- MINOR = 4
5
- PATCH = 0
5
+ MAJOR = 3
6
+ MINOR = 0
7
+ PATCH = 2
6
8
 
7
9
  VER_STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu-plugins-ssl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sensu-Plugins and contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-21 00:00:00.000000000 Z
11
+ date: 2020-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sensu-plugin
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.2'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.2'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.7'
33
+ version: '2.1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.7'
40
+ version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: codeclimate-test-reporter
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.3'
61
+ version: '3.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.3'
68
+ version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '13.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '10.0'
96
+ version: '13.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: redcarpet
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,53 +128,56 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.40.0
131
+ version: 0.89.1
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.40.0
138
+ version: 0.89.1
139
139
  - !ruby/object:Gem::Dependency
140
- name: yard
140
+ name: timecop
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.8'
145
+ version: 0.8.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0.8'
152
+ version: 0.8.0
153
153
  - !ruby/object:Gem::Dependency
154
- name: timecop
154
+ name: yard
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: 0.8.0
159
+ version: '0.8'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: 0.8.0
166
+ version: '0.8'
167
167
  description: |-
168
168
  This plugin provides native SSL instrumentation
169
169
  for monitoring, including: hostname and chain
170
170
  verification, cert and crl expiry, and Qualys SSL Labs reporting
171
171
  email: "<sensu-users@googlegroups.com>"
172
172
  executables:
173
- - check-java-keystore-cert.rb
174
- - check-ssl-anchor.rb
173
+ - check-ssl-hsts-status.rb
174
+ - check-ssl-root-issuer.rb
175
175
  - check-ssl-cert.rb
176
+ - check-java-keystore-cert.rb
176
177
  - check-ssl-crl.rb
178
+ - check-ssl-anchor.rb
177
179
  - check-ssl-host.rb
180
+ - check-ssl-hsts-preloadable.rb
178
181
  - check-ssl-qualys.rb
179
182
  extensions: []
180
183
  extra_rdoc_files: []
@@ -187,7 +190,10 @@ files:
187
190
  - bin/check-ssl-cert.rb
188
191
  - bin/check-ssl-crl.rb
189
192
  - bin/check-ssl-host.rb
193
+ - bin/check-ssl-hsts-preloadable.rb
194
+ - bin/check-ssl-hsts-status.rb
190
195
  - bin/check-ssl-qualys.rb
196
+ - bin/check-ssl-root-issuer.rb
191
197
  - lib/sensu-plugins-ssl.rb
192
198
  - lib/sensu-plugins-ssl/version.rb
193
199
  homepage: https://github.com/sensu-plugins/sensu-plugins-ssl
@@ -208,15 +214,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
214
  requirements:
209
215
  - - ">="
210
216
  - !ruby/object:Gem::Version
211
- version: 2.0.0
217
+ version: 2.4.0
212
218
  required_rubygems_version: !ruby/object:Gem::Requirement
213
219
  requirements:
214
220
  - - ">="
215
221
  - !ruby/object:Gem::Version
216
222
  version: '0'
217
223
  requirements: []
218
- rubyforge_project:
219
- rubygems_version: 2.4.5
224
+ rubygems_version: 3.0.8
220
225
  signing_key:
221
226
  specification_version: 4
222
227
  summary: Sensu plugins for SSL