... |
... |
@@ -1,0 +1,319 @@ |
|
1 |
+#!/bin/bash |
|
2 |
+ |
|
3 |
+# This generates and signs your required certificates. Please do not |
|
4 |
+# forget to install the Icinga 2 package and your desired monitoring |
|
5 |
+# plugins first. |
|
6 |
+ |
|
7 |
+# Config from Director |
|
8 |
+ICINGA2_NODENAME='private-cloud-taunusstein-master' |
|
9 |
+ICINGA2_CA_TICKET='c892a4ef8afe567e67db5beaf363f8c9b498a7ad' |
|
10 |
+ICINGA2_PARENT_ZONE='monitoring-sat-fsn02.xima-services.de' |
|
11 |
+ICINGA2_PARENT_ENDPOINTS=('monitoring-sat-fsn02.xima-services.de,monitoring-sat-fsn02.xima-services.de') |
|
12 |
+ICINGA2_CA_NODE='monitoring.xima-services.de' |
|
13 |
+ICINGA2_GLOBAL_ZONES=('director-global') |
|
14 |
+ |
|
15 |
+# Internal defaults |
|
16 |
+: "${ICINGA2_OSFAMILY:=}" |
|
17 |
+: "${ICINGA2_HOSTNAME:="$(hostname -f)"}" |
|
18 |
+: "${ICINGA2_NODENAME:="${ICINGA2_HOSTNAME}"}" |
|
19 |
+: "${ICINGA2_CA_NODE:=}" |
|
20 |
+: "${ICINGA2_CA_PORT:=5665}" |
|
21 |
+: "${ICINGA2_CA_TICKET:=}" |
|
22 |
+: "${ICINGA2_PARENT_ZONE:=master}" |
|
23 |
+: "${ICINGA2_PARENT_ENDPOINTS:=()}" |
|
24 |
+: "${ICINGA2_GLOBAL_ZONES:=director-global}" |
|
25 |
+: "${ICINGA2_DRYRUN:=}" |
|
26 |
+: "${ICINGA2_UPDATE_CONFIG:=}" |
|
27 |
+ |
|
28 |
+# Helper functions |
|
29 |
+fail() { |
|
30 |
+ echo "ERROR: $1" >&2 |
|
31 |
+ exit 1 |
|
32 |
+} |
|
33 |
+ |
|
34 |
+warn() { |
|
35 |
+ echo "WARNING: $1" >&2 |
|
36 |
+} |
|
37 |
+ |
|
38 |
+info() { |
|
39 |
+ echo "INFO: $1" >&2 |
|
40 |
+} |
|
41 |
+ |
|
42 |
+check_command() { |
|
43 |
+ command -v "$@" &>/dev/null |
|
44 |
+} |
|
45 |
+ |
|
46 |
+install_config() { |
|
47 |
+ if [ -e "$1" ] && [ ! -e "${1}.orig" ]; then |
|
48 |
+ info "Creating a backup at ${1}.orig" |
|
49 |
+ cp "$1" "${1}.orig" |
|
50 |
+ fi |
|
51 |
+ echo "Writing config to ${1}" |
|
52 |
+ echo "$2" > "${1}" |
|
53 |
+} |
|
54 |
+ |
|
55 |
+[ "$BASH_VERSION" ] || fail "This is a Bash script" |
|
56 |
+ |
|
57 |
+errors= |
|
58 |
+for key in NODENAME CA_NODE CA_PORT CA_TICKET PARENT_ZONE PARENT_ENDPOINTS; do |
|
59 |
+ var="ICINGA2_${key}" |
|
60 |
+ if [ -z "${!var}" ]; then |
|
61 |
+ warn "The variable $var needs to be configured!" |
|
62 |
+ errors+=1 |
|
63 |
+ fi |
|
64 |
+done |
|
65 |
+[ -z "$errors" ] || exit 1 |
|
66 |
+ |
|
67 |
+# Detect osfamily |
|
68 |
+if [ -n "$ICINGA2_OSFAMILY" ]; then |
|
69 |
+ info "Assuming supplied osfamily $ICINGA2_OSFAMILY" |
|
70 |
+elif check_command rpm && ! check_command dpkg; then |
|
71 |
+ info "This should be a RedHat system" |
|
72 |
+ if [ -e /etc/sysconfig/icinga2 ]; then |
|
73 |
+ # shellcheck disable=SC1091 |
|
74 |
+ . /etc/sysconfig/icinga2 |
|
75 |
+ fi |
|
76 |
+ ICINGA2_OSFAMILY=redhat |
|
77 |
+elif check_command dpkg; then |
|
78 |
+ info "This should be a Debian system" |
|
79 |
+ if [ -e /etc/default/icinga2 ]; then |
|
80 |
+ # shellcheck disable=SC1091 |
|
81 |
+ . /etc/default/icinga2 |
|
82 |
+ fi |
|
83 |
+ ICINGA2_OSFAMILY=debian |
|
84 |
+elif check_command apk; then |
|
85 |
+ info "This should be a Alpine system" |
|
86 |
+ if [ -e /etc/icinga2/icinga2.sysconfig ]; then |
|
87 |
+ # shellcheck disable=SC1091 |
|
88 |
+ . /etc/icinga2/icinga2.sysconfig |
|
89 |
+ fi |
|
90 |
+ ICINGA2_OSFAMILY=alpine |
|
91 |
+else |
|
92 |
+ fail "Could not determine your os type!" |
|
93 |
+fi |
|
94 |
+ |
|
95 |
+# internal defaults |
|
96 |
+: "${ICINGA2_CONFIG_FILE:=/etc/icinga2/icinga2.conf}" |
|
97 |
+: "${ICINGA2_CONFIGDIR:="$(dirname "$ICINGA2_CONFIG_FILE")"}" |
|
98 |
+: "${ICINGA2_DATADIR:=/var/lib/icinga2}" |
|
99 |
+: "${ICINGA2_SSLDIR_OLD:="${ICINGA2_CONFIGDIR}"/pki}" |
|
100 |
+: "${ICINGA2_SSLDIR_NEW:="${ICINGA2_DATADIR}"/certs}" |
|
101 |
+: "${ICINGA2_SSLDIR:=}" |
|
102 |
+: "${ICINGA2_BIN:=icinga2}" |
|
103 |
+ |
|
104 |
+case "$ICINGA2_OSFAMILY" in |
|
105 |
+debian) |
|
106 |
+ : "${ICINGA2_USER:=nagios}" |
|
107 |
+ : "${ICINGA2_GROUP:=nagios}" |
|
108 |
+ ;; |
|
109 |
+redhat) |
|
110 |
+ : "${ICINGA2_USER:=icinga}" |
|
111 |
+ : "${ICINGA2_GROUP:=icinga}" |
|
112 |
+ ;; |
|
113 |
+alpine) |
|
114 |
+ : "${ICINGA2_USER:=icinga}" |
|
115 |
+ : "${ICINGA2_GROUP:=icinga}" |
|
116 |
+ ;; |
|
117 |
+*) |
|
118 |
+ fail "Unknown osfamily '$ICINGA2_OSFAMILY'!" |
|
119 |
+ ;; |
|
120 |
+esac |
|
121 |
+ |
|
122 |
+icinga_version() { |
|
123 |
+ "$ICINGA2_BIN" --version 2>/dev/null | grep -oPi '\(version: [rv]?\K\d+\.\d+\.\d+[^\)]*' |
|
124 |
+} |
|
125 |
+ |
|
126 |
+version() { |
|
127 |
+ echo "$@" | awk -F. '{ printf("%03d%03d%03d\n", $1,$2,$3); }' |
|
128 |
+} |
|
129 |
+ |
|
130 |
+# Make sure icinga2 is installed and running |
|
131 |
+echo -n "check: icinga2 installed - " |
|
132 |
+if version=$(icinga_version); then |
|
133 |
+ echo "OK: $version" |
|
134 |
+else |
|
135 |
+ fail "You need to install icinga2!" |
|
136 |
+fi |
|
137 |
+ |
|
138 |
+if [ -z "${ICINGA2_SSLDIR}" ]; then |
|
139 |
+ if [ -f "${ICINGA2_SSLDIR_OLD}/${ICINGA2_NODENAME}.crt" ]; then |
|
140 |
+ info "Using old SSL directory: ${ICINGA2_SSLDIR_OLD}" |
|
141 |
+ info "Because you already have a certificate in ${ICINGA2_SSLDIR_OLD}/${ICINGA2_NODENAME}.crt" |
|
142 |
+ ICINGA2_SSLDIR="${ICINGA2_SSLDIR_OLD}" |
|
143 |
+ elif [ $(version $version) -gt $(version 2.8) ]; then |
|
144 |
+ info "Using new SSL directory: ${ICINGA2_SSLDIR_NEW}" |
|
145 |
+ ICINGA2_SSLDIR="${ICINGA2_SSLDIR_NEW}" |
|
146 |
+ else |
|
147 |
+ info "Using old SSL directory: ${ICINGA2_SSLDIR_OLD}" |
|
148 |
+ ICINGA2_SSLDIR="${ICINGA2_SSLDIR_OLD}" |
|
149 |
+ fi |
|
150 |
+fi |
|
151 |
+ |
|
152 |
+if [ ! -d "$ICINGA2_SSLDIR" ]; then |
|
153 |
+ mkdir "$ICINGA2_SSLDIR" |
|
154 |
+ chown "$ICINGA2_USER.$ICINGA2_GROUP" "$ICINGA2_SSLDIR" |
|
155 |
+fi |
|
156 |
+ |
|
157 |
+if [ -f "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.crt" ]; then |
|
158 |
+ warn "ERROR: a certificate for '${ICINGA2_NODENAME}' already exists" |
|
159 |
+ warn "Please remove ${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.??? in case you want a" |
|
160 |
+ warn "new certificate to be generated and signed by ${ICINGA2_CA_NODE}" |
|
161 |
+ |
|
162 |
+ if [ -z "${ICINGA2_UPDATE_CONFIG}" ] && [ -z "${ICINGA2_DRYRUN}" ]; then |
|
163 |
+ warn "Aborting here, you can can call the script like this to just update config:" |
|
164 |
+ info " ICINGA2_UPDATE_CONFIG=1 $0" |
|
165 |
+ exit 1 |
|
166 |
+ fi |
|
167 |
+elif [ -z "${ICINGA2_DRYRUN}" ]; then |
|
168 |
+ if ! "$ICINGA2_BIN" pki new-cert --cn "${ICINGA2_NODENAME}" \ |
|
169 |
+ --cert "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.crt" \ |
|
170 |
+ --csr "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.csr" \ |
|
171 |
+ --key "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.key" |
|
172 |
+ then fail "Could not create self signed certificate!" |
|
173 |
+ fi |
|
174 |
+ |
|
175 |
+ if ! "$ICINGA2_BIN" pki save-cert \ |
|
176 |
+ --host "${ICINGA2_CA_NODE}" \ |
|
177 |
+ --port "${ICINGA2_CA_PORT}" \ |
|
178 |
+ --key "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.key" \ |
|
179 |
+ --trustedcert "${ICINGA2_SSLDIR}/trusted-master.crt" |
|
180 |
+ then fail "Could not retrieve trusted certificate from host ${ICINGA2_CA_NODE}" |
|
181 |
+ fi |
|
182 |
+ |
|
183 |
+ if ! "$ICINGA2_BIN" pki request \ |
|
184 |
+ --host "${ICINGA2_CA_NODE}" \ |
|
185 |
+ --port "${ICINGA2_CA_PORT}" \ |
|
186 |
+ --ticket "${ICINGA2_CA_TICKET}" \ |
|
187 |
+ --key "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.key" \ |
|
188 |
+ --cert "${ICINGA2_SSLDIR}/${ICINGA2_NODENAME}.crt" \ |
|
189 |
+ --trustedcert "${ICINGA2_SSLDIR}/trusted-master.crt" \ |
|
190 |
+ --ca "${ICINGA2_SSLDIR}/ca.crt" |
|
191 |
+ then fail "Could not retrieve final certificate from host ${ICINGA2_CA_NODE}" |
|
192 |
+ fi |
|
193 |
+else |
|
194 |
+ info "Would create certificates under ${ICINGA2_SSLDIR}, but in dry-run!" |
|
195 |
+fi |
|
196 |
+ |
|
197 |
+# Prepare Config Files |
|
198 |
+content_config=$(cat << EOF |
|
199 |
+/** Icinga 2 Config - proposed by Icinga Director */ |
|
200 |
+ |
|
201 |
+include "constants.conf" |
|
202 |
+ |
|
203 |
+$([ "${ICINGA2_HOSTNAME}" != "${ICINGA2_NODENAME}" ] || echo '// ')const NodeName = "${ICINGA2_NODENAME}" |
|
204 |
+ |
|
205 |
+include "zones.conf" |
|
206 |
+include "features-enabled/*.conf" |
|
207 |
+ |
|
208 |
+include <itl> |
|
209 |
+include <plugins> |
|
210 |
+include <plugins-contrib> |
|
211 |
+include <manubulon> |
|
212 |
+include <windows-plugins> |
|
213 |
+include <nscp> |
|
214 |
+EOF |
|
215 |
+) |
|
216 |
+ |
|
217 |
+endpoint_list='' |
|
218 |
+for item in "${ICINGA2_PARENT_ENDPOINTS[@]}"; do |
|
219 |
+ endpoint=$(echo "$item" | cut -d, -f1) |
|
220 |
+ endpoint_list+="\"${endpoint}\", " |
|
221 |
+done |
|
222 |
+ |
|
223 |
+content_zones=$(cat << EOF |
|
224 |
+/** Icinga 2 Config - proposed by Icinga Director */ |
|
225 |
+ |
|
226 |
+object Endpoint "${ICINGA2_NODENAME}" {} |
|
227 |
+ |
|
228 |
+object Zone "${ICINGA2_NODENAME}" { |
|
229 |
+ parent = "${ICINGA2_PARENT_ZONE}" |
|
230 |
+ endpoints = [ "${ICINGA2_NODENAME}" ] |
|
231 |
+} |
|
232 |
+ |
|
233 |
+object Zone "${ICINGA2_PARENT_ZONE}" { |
|
234 |
+ endpoints = [ ${endpoint_list%, } ] |
|
235 |
+} |
|
236 |
+EOF |
|
237 |
+) |
|
238 |
+ |
|
239 |
+for item in "${ICINGA2_PARENT_ENDPOINTS[@]}"; do |
|
240 |
+ endpoint=$(echo "$item" | cut -d, -f1) |
|
241 |
+ host=$(echo "$item" | cut -s -d, -f2) |
|
242 |
+ |
|
243 |
+ content_zones+=$(cat << EOF |
|
244 |
+ |
|
245 |
+object Endpoint "${endpoint}" { |
|
246 |
+$([ -n "$host" ] && echo " host = \"${host}\"" || echo " //host = \"${endpoint}\"") |
|
247 |
+} |
|
248 |
+EOF |
|
249 |
+) |
|
250 |
+done |
|
251 |
+ |
|
252 |
+for zone in "${ICINGA2_GLOBAL_ZONES[@]}"; do |
|
253 |
+ content_zones+=$(cat << EOF |
|
254 |
+ |
|
255 |
+object Zone "${zone}" { |
|
256 |
+ global = true |
|
257 |
+} |
|
258 |
+EOF |
|
259 |
+) |
|
260 |
+done |
|
261 |
+ |
|
262 |
+content_api="/** Icinga 2 Config - proposed by Icinga Director */ |
|
263 |
+ |
|
264 |
+object ApiListener \"api\" {" |
|
265 |
+ |
|
266 |
+if [ "${ICINGA2_SSLDIR}" = "${ICINGA2_SSLDIR_OLD}" ]; then |
|
267 |
+content_api+=" |
|
268 |
+ cert_path = SysconfDir + \"/icinga2/pki/${ICINGA2_NODENAME}.crt\" |
|
269 |
+ key_path = SysconfDir + \"/icinga2/pki/${ICINGA2_NODENAME}.key\" |
|
270 |
+ ca_path = SysconfDir + \"/icinga2/pki/ca.crt\" |
|
271 |
+" |
|
272 |
+fi |
|
273 |
+content_api+=" |
|
274 |
+ accept_commands = true |
|
275 |
+ accept_config = true |
|
276 |
+} |
|
277 |
+" |
|
278 |
+ |
|
279 |
+if [ -z "${ICINGA2_DRYRUN}" ]; then |
|
280 |
+ install_config "$ICINGA2_CONFIGDIR"/icinga2.conf "$content_config" |
|
281 |
+ install_config "$ICINGA2_CONFIGDIR"/zones.conf "$content_zones" |
|
282 |
+ install_config "$ICINGA2_CONFIGDIR"/features-available/api.conf "$content_api" |
|
283 |
+ |
|
284 |
+ "$ICINGA2_BIN" feature enable api |
|
285 |
+ |
|
286 |
+ "$ICINGA2_BIN" daemon -C |
|
287 |
+ |
|
288 |
+ echo "Please restart icinga2:" |
|
289 |
+ case "$ICINGA2_OSFAMILY" in |
|
290 |
+ debian) |
|
291 |
+ echo " systemctl restart icinga2" |
|
292 |
+ ;; |
|
293 |
+ redhat) |
|
294 |
+ echo " systemctl restart icinga2" |
|
295 |
+ ;; |
|
296 |
+ alpine) |
|
297 |
+ echo " rc-service icinga2 restart" |
|
298 |
+ ;; |
|
299 |
+ *) |
|
300 |
+ fail "Unknown osfamily '$ICINGA2_OSFAMILY'!" |
|
301 |
+ ;; |
|
302 |
+ esac |
|
303 |
+else |
|
304 |
+ output_code() { |
|
305 |
+ sed 's/^/ /m' <<<"$1" |
|
306 |
+ } |
|
307 |
+ echo "### $ICINGA2_CONFIGDIR"/icinga2.conf |
|
308 |
+ echo |
|
309 |
+ output_code "$content_config" |
|
310 |
+ echo |
|
311 |
+ echo "### $ICINGA2_CONFIGDIR"/zones.conf |
|
312 |
+ echo |
|
313 |
+ output_code "$content_zones" |
|
314 |
+ echo |
|
315 |
+ echo "### $ICINGA2_CONFIGDIR"/features-available/api.conf |
|
316 |
+ echo |
|
317 |
+ output_code "$content_api" |
|
318 |
+fi |
|
319 |
+ |