-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheck_openssl_ca
More file actions
executable file
·250 lines (227 loc) · 7.65 KB
/
check_openssl_ca
File metadata and controls
executable file
·250 lines (227 loc) · 7.65 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#!/bin/bash
#
# Copyright(C) 2021 ZENETYS
# This script is licensed under MIT License (http://opensource.org/licenses/MIT)
# License: License MIT
# Initial author: Julien THOMAS < jthomas @ zenetys.com >
#
set -f
PROGNAME=${0##*/}
NAGIOS_STATUS_TEXT=(
[0]='OK'
[1]='WARNING'
[2]='CRITICAL'
[3]='UNKNOWN'
)
NAGIOS_STATUS_PRIO_TR=( 0 2 3 1 )
DIR=
INDEX=index
WARNING=
CRITICAL=
IGNORE_EXPIRED=
VERBOSE=
SSH_HOST=
SSH_USER=
SSH_PORT=
TIMEOUT=5 # SSH ConnectTimeout
SSH_IDENTITY=
SUDO_USER=
function nagios_exit_usage() {
echo "\
Usage: $PROGNAME [OPTION...] -d DIRECTORY -w WARNING -c CRITICAL
Nagios plugin to check for certificates expiration in an OpenSSL CA
Common options:
-d, --directory DIR OpenSSL CA base directory
-i, --index FNAME OpenSSL CA database filename
-w, --warning INT Days left before expiration, warning threshold
-c, --critical INT Days left before expiration, critical threshold
-E, --ignore-expired Do not warn on expired certificates not revoked
-v, --verbose Increase verbose level (see below)
-vv Shortcut for verbose level 2
-S, --sudo-user USER Read CA index with sudo -u USER cat
-h, --help Display this help
SSH options:
-H, --host HOST SSH host, enable to retrieve CA index via SSH
-u, --user USER SSH username
-p, --port INT SSH port
-i, --identity FILE SSH identity key file
-t, --timeout INT SSH connect timeout
Verbosity level 1: detail of each certificate in alert in long plugin output
Verbosity level 2: add CN of certificates in alert in plugin output"
exit 3
}
# $1: Nagios status code
# $2: Plugin output message
# $@: Optional lines of long plugin output
function nagios_die() {
echo "${NAGIOS_STATUS_TEXT[$1]}: $2"
(( $# > 2 )) && (IFS=$'\n'; echo "${*:3}")
exit "$1"
}
# $1: x509 subject, parts separated by slash
function get_cn() {
REPLY=
local re='/CN=([^/]+)'
[[ $1 =~ $re ]] || return 1
REPLY=${BASH_REMATCH[1]}
}
# $1: current state
# $2: want state
function increase_prio() {
REPLY=$1
if (( NAGIOS_STATUS_PRIO_TR[$2] > NAGIOS_STATUS_PRIO_TR[$1] )); then
REPLY=$2
fi
}
function get_openssl_ca_index() {
local cmd=( ${SUDO_USER:+sudo -u "$SUDO_USER"} cat "$DIR/$INDEX" )
local sshopts sshargs
if [[ -n $SSH_HOST ]]; then
sshopts=(
${SSH_IDENTITY:+-i "$SSH_IDENTITY"} ${SSH_USER:+-l "$SSH_USER"}
${SSH_PORT:+-p "$SSH_PORT"} -q -C -T -o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null -o PreferredAuthentications=publickey
${TIMEOUT:+-o "ConnectTimeout=$TIMEOUT"}
)
printf -v sshargs "%q " "${cmd[@]}"
cmd=( ssh "${sshopts[@]}" "$SSH_HOST" -- "$sshargs" )
fi
REPLY=$( "${cmd[@]}" )
}
while (( $# > 0 )); do
case "$1" in
# common
-d|--directory) DIR=$2; shift ;;
-i|--index) INDEX=$2; shift ;;
-w|--warning) WARNING=$2; shift ;;
-c|--critical) CRITICAL=$2; shift ;;
-E|--ignore-expired) IGNORE_EXPIRED=1 ;;
-v|--verbose) (( VERBOSE++ )) ;;
-vv) (( VERBOSE += 2 )) ;;
-S|--sudo-user) SUDO_USER=$2; shift ;;
-h|--help) nagios_exit_usage 3 ;;
# ssh
-H|--host) SSH_HOST=$2; shift ;;
-u|--user) SSH_USER=$2; shift ;;
-p|--port) SSH_PORT=$2; shift ;;
-i|--identity) SSH_IDENTITY=$2; shift ;;
-t|--timeout) TIMEOUT=$2; shift ;;
esac
shift
done
if [[ -z $DIR ]]; then
nagios_die 3 'Missing OpenSSL CA directory'
fi
if [[ -z $WARNING || -n ${WARNING//[0-9]} ]]; then
nagios_die 3 'Invalid warning threshold, integer expected'
fi
if [[ -z $CRITICAL || -n ${CRITICAL//[0-9]} ]]; then
nagios_die 3 'Invalid critical threshold, integer expected'
fi
if (( WARNING < CRITICAL )); then
nagios_die 3 'Invalid thresholds, warning is lower than critical'
fi
if [[ -n $SSH_PORT && -n ${SSH_PORT//[0-9]} ]]; then
nagios_die 3 'Invalid SSH port, integer expected'
fi
if [[ -n $TIMEOUT && -n ${TIMEOUT//[0-9]} ]]; then
nagios_die 3 'Invalid SSH connect timeout, integer expected'
fi
if [[ -n $SSH_IDENTITY && ! -r $SSH_IDENTITY ]]; then
nagios_die 3 'Cannot read SSH identity file'
fi
now=$(date +%s)
if [[ -z $now ]]; then
nagios_die 3 'Failed to get current time'
fi
if ! get_openssl_ca_index; then
nagios_die 3 "Failed to retrive CA database $DIR/index"
fi
openssl_ca_index=$REPLY
info_unknown=
info_warning=
info_critical=
info_expired=
detail_unknown=()
detail_warning=()
detail_critical=()
detail_expired=()
status=0
output=
# assume openssl ca index file is valid
# fields 0, 1, 3 and 5 are used
while IFS=$'\x16' read -r -a REPLY; do
flag=${REPLY[0]}
expire=${REPLY[1]}
serial=${REPLY[3]}
subject=${REPLY[5]}
get_cn "$subject"; cn=$REPLY
if [[ -n $cn ]]; then
id="0x$serial, CN=$cn"
name=$cn
else
id="0x$serial, CN=?"
name=$serial
fi
# ignore revoked certificates
[[ $flag == *R* ]] && continue
# expire timestamp
# 2 vs 4 digits year, eg: 271103103225Z vs 20271122230000Z
(( ${#expire} == 13 )) && expire="20$expire"
expire=$(date -d "${expire:0:4}-${expire:4:2}-${expire:6:2} ${expire:8:2}:${expire:10:2}:${expire:12}" +%s)
if [[ -z $expire ]]; then
info_unknown+="${info_critical:+, }$name"
detail_unknown+=( "Certificate $id, cannot read expire date" )
increase_prio "$status" 3; status=$REPLY
continue
fi
days_before_expire=$(( (expire - now) / 3600 / 24 ))
if (( days_before_expire >= 0 )); then
if (( days_before_expire <= CRITICAL )); then
info_critical+="${info_critical:+, }$name (${days_before_expire}d)"
detail_critical+=( "Certificate $id, expire in ${days_before_expire}d" )
increase_prio "$status" 2; status=$REPLY
elif (( days_before_expire <= WARNING )); then
info_warning+="${info_warning:+, }$name (${days_before_expire}d)"
detail_warning+=( "Certificate $id, expire in ${days_before_expire}d" )
increase_prio "$status" 1; status=$REPLY
fi
elif [[ -z $IGNORE_EXPIRED ]]; then # already expired
info_expired+="${info_expired:+, }$name"
detail_expired+=( "Certificate $id, expired $(( -days_before_expire ))d ago but not revoked" )
increase_prio "$status" 1; status=$REPLY
fi
done < <(echo "$openssl_ca_index" |sed -re 's,\t,\x16,g' |sort -t $'\x16' -k 2,2)
if (( ${#detail_critical[@]} > 0 )); then
cert=cert; (( ${#detail_critical[@]} > 1 )) && cert+=s
output+="${output:+ }${#detail_critical[@]} $cert expire <= ${CRITICAL}d"
(( VERBOSE > 1 )) && output+=": $info_critical"
output+=.
fi
if (( ${#detail_warning[@]} > 0 )); then
cert=cert; (( ${#detail_warning[@]} > 1 )) && cert+=s
output+="${output:+ }${#detail_warning[@]} $cert expire <= ${WARNING}d"
(( VERBOSE > 1 )) && output+=": $info_warning"
output+=.
fi
if (( ${#detail_expired[@]} > 0 )); then
cert=cert; (( ${#detail_expired[@]} > 1 )) && cert+=s
output+="${output:+ }${#detail_expired[@]} $cert expired not revoked"
(( VERBOSE > 1 )) && output+=": $info_expired"
output+=.
fi
if (( ${#detail_unknown[@]} > 0 )); then
cert=cert; (( ${#detail_unknown[@]} > 1 )) && cert+=s
output+="${output:+ }${#detail_unknown[@]} $cert unknown"
(( VERBOSE > 1 )) && output+=": $info_unknown"
output+=.
fi
if (( VERBOSE == 0 )); then
nagios_die "$status" "${output:-No certificate in alert}"
else
nagios_die "$status" "${output:-No certificate in alert}" \
"${detail_critical[@]}" \
"${detail_warning[@]}" \
"${detail_expired[@]}" \
"${detail_unknown[@]}"
fi