-
Notifications
You must be signed in to change notification settings - Fork 47
/
check-ssl-qualys.rb
executable file
·143 lines (126 loc) · 4.02 KB
/
check-ssl-qualys.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env ruby
# encoding: UTF-8
# check-ssl-qualys.rb
#
# DESCRIPTION:
# Runs a report using the Qualys SSL Labs API and then alerts if a
# domain does not meet the grade specified for *ALL* hosts that are
# reachable from that domian.
#
# The checks that are performed are documented on
# https://www.ssllabs.com/index.html as are the range of grades.
#
# OUTPUT:
# plain text
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
#
# USAGE:
# # Basic usage
# check-ssl-qualys.rb -d <domain_name>
# # Specify the CRITICAL and WARNING grades to a specific grade
# check-ssl-qualys.rb -d <domain_name> -c <critical_grade> -w <warning_grade>
# # Use --api-url to specify an alternate api host
# check-ssl-qualys.rb -d <domain_name> -api-url <alternate_host>
#
# NOTE: This check takes a rather long time to run and will timeout if you're using
# the default sensu check timeout. Make sure to set a longer timeout period in the
# check definition. Two minutes or longer may be a good starting point as checks
# regularly take 90+ seconds to run.
#
# LICENSE:
# Copyright 2015 William Cooke <will@bruisyard.eu>
# Released under the same terms as Sensu (the MIT license); see LICENSE for
# details.
#
require 'sensu-plugin/check/cli'
require 'json'
require 'net/http'
# Checks a single DNS entry has a rating above a certain level
class CheckSSLQualys < Sensu::Plugin::Check::CLI
# Current grades that are avaialble from the API
GRADE_OPTIONS = ['A+', 'A', 'A-', 'B', 'C', 'D', 'E', 'F', 'T', 'M'].freeze
option :domain,
description: 'The domain to run the test against',
short: '-d DOMAIN',
long: '--domain DOMAIN',
required: true
option :api_url,
description: 'The URL of the API to run against',
long: '--api-url URL',
default: 'https://api.ssllabs.com/api/v2/'
option :warn,
short: '-w GRADE',
long: '--warn GRADE',
description: 'WARNING if below this grade',
proc: proc { |g| GRADE_OPTIONS.index(g) },
default: 2 # 'A-'
option :critical,
short: '-c GRADE',
long: '--critical GRADE',
description: 'CRITICAL if below this grade',
proc: proc { |g| GRADE_OPTIONS.index(g) },
default: 3 # 'B'
option :num_checks,
short: '-n NUM_CHECKS',
long: '--number-checks NUM_CHECKS',
description: 'The number of checks to make before giving up (timeout of check)',
proc: proc { |t| t.to_i },
default: 24
option :between_checks,
short: '-t SECONDS',
long: '--time-between SECONDS',
description: 'The time between each poll of the API',
proc: proc { |t| t.to_i },
default: 10
def ssl_api_request(from_cache)
params = { host: config[:domain] }
params[:startNew] = 'on' unless from_cache
uri = URI("#{config[:api_url]}analyze")
uri.query = URI.encode_www_form(params)
response = Net::HTTP.get_response(uri)
warning 'Bad response recieved from API' unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
def ssl_check(from_cache)
json = ssl_api_request(from_cache)
warning "ERROR on #{config[:domain]} check" if json['status'] == 'ERROR'
json
end
def ssl_recheck
1.upto(config[:num_checks]) do |step|
json = ssl_check(step != 1)
return json if json['status'] == 'READY'
sleep(config[:between_checks])
end
warning 'Timeout waiting for check to finish'
end
def ssl_grades
ssl_recheck['endpoints'].map do |endpoint|
endpoint['grade']
end
end
def lowest_grade
ssl_grades.sort_by! { |g| GRADE_OPTIONS.index(g) } .reverse![0]
end
def run
grade = lowest_grade
unless grade
message "#{config[:domain]} not rated"
critical
end
message "#{config[:domain]} rated #{grade}"
grade_rank = GRADE_OPTIONS.index(grade)
if grade_rank > config[:critical]
critical
elsif grade_rank > config[:warn]
warning
else
ok
end
end
end