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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
|
#!/bin/sh
: ${icinga_threads:="$nproc"}
: ${icinga_dbname:='icinga'}
: ${icinga_dbhost:="$postgres_host"}
: ${icinga_password:='changeme'}
: ${icinga_ticket_salt:='changeme'}
: ${icingaweb_api_password:='changeme'}
: ${icingaweb_dbhost:="$postgres_host"}
: ${icingaweb_dbname:='icingaweb'}
: ${icingaweb_access_role:='icinga-access'}
# Note that icinga does not support nested groups.
: ${icingaweb_admin_groups:=''}
: ${icinga_fqdn:="$fqdn"}
: ${icinga_notification_mail_from:="Icinga <icinga-noreply@${email_domain}>"}
: ${icinga_notification_mail_to:="changeme@${email_domain}"}
: ${icinga_smtp_mail_from:="${icinga_username}@${fqdn}"}
: ${icinga_smtp_rcpt_to:="someuser@${email_domain}"}
: ${icinga_lmtp_rcpt_to:='someuser'}
: ${icinga_upstream_ping_address:='8.8.8.8'}
: ${icinga_upstream_packet_loss_warn:='5'}
: ${icinga_upstream_packet_loss_crit:='15'}
: ${icinga_upstream_latency_warn:='250'}
: ${icinga_upstream_latency_crit:='500'}
: ${icinga_upstream_packet_count:='5'}
: ${icinga_mailq_warn:='1'}
: ${icinga_mailq_crit:='5'}
: ${icinga_cert_days_warn:='30'}
: ${icinga_cert_days_crit:='20'}
: ${icinga_response_time_warn:='0.5'}
: ${icinga_response_time_crit:='1.0'}
icinga_dn="uid=${icinga_username},${robots_basedn}"
icinga_conf_dir=/usr/local/etc/icinga2
icinga_data_dir=/var/lib/icinga2
icinga_cert_dir="${icinga_data_dir}/certs"
icinga_ca_dir="${icinga_data_dir}/ca"
icinga_tls_client_cert="${icinga_home_dir}/${icinga_username}.crt"
icinga_tls_client_key="${icinga_home_dir}/${icinga_username}.key"
icingadb_conf_dir=/usr/local/etc/icingadb
icingaweb_api_username=icingaweb2
icingaweb_https_cert="${nginx_conf_dir}/icingaweb.crt"
icingaweb_https_key="${nginx_conf_dir}/icingaweb.key"
icingaweb_install_dir=/usr/local/www/icingaweb2
icingaweb_webroot="${icingaweb_install_dir}/public"
icingaweb_conf_dir=/usr/local/etc/icingaweb2
icingaweb_fpm_socket=/var/run/fpm-icingaweb.sock
icingaweb_client_keytab="${keytab_dir}/icingaweb.client.keytab"
nginx_keytab="${keytab_dir}/nginx.keytab"
redis_user=redis
redis_data_dir=/var/db/redis
redis_sock=/var/run/redis/redis.sock
redis_port=6379
redis_data_dir=/var/db/redis
icinga_psql(){
KRB5CCNAME=MEMORY: KRB5_CLIENT_KTNAME="$icingaweb_client_keytab" \
psql \
--quiet --no-align --tuples-only --echo-all \
--host="$icinga_dbhost" \
--dbname="$icinga_dbname" \
--username="$icinga_username" \
--no-password \
"$@"
}
icingaweb_psql(){
KRB5CCNAME=MEMORY: KRB5_CLIENT_KTNAME="$icingaweb_client_keytab" \
psql \
--quiet --no-align --tuples-only --echo-all \
--host="$icingaweb_dbhost" \
--dbname="$icingaweb_dbname" \
--username="$icinga_username" \
--no-password \
"$@"
}
# Install packages.
pkg install -y \
icinga2 \
icingadb \
icingaweb2-php${php_version} \
icingaweb2-module-icingadb-php${php_version} \
nginx \
redis \
wpa_supplicant
# Fix icinga's home directory. ports/UIDs file is wrong.
pw user mod "$icinga_local_user" -d "$icinga_home_dir"
rm -rf /var/spool/icinga
# Create dataset for icinga state directory
create_dataset -o "mountpoint=${icinga_data_dir}" "${state_dataset}/icinga"
install_directory -m 0755 -o "$icinga_local_user" -g "$icinga_local_user" "$icinga_data_dir"
# Create icinga LDAP user, principal, and keytab.
# Note that we have a separate userPassword attribute in LDAP because icingadb is
# written in golang, and it's pq library does not build with GSSAPI support.
# GSSAPI is supported by icingaweb2 via PHP's PDO, however, so we use it there.
# We also need a userPassword attribute for icingaweb2 authn/authz.
ldap_add "$icinga_dn" <<EOF
objectClass: account
objectClass: simpleSecurityObject
uid: ${icinga_username}
userPassword: {SSHA-512}
EOF
ldap_passwd "$icinga_dn" "$icinga_password"
add_principal -nokey -x "dn=${icinga_dn}" "$icinga_username"
ktadd -k "$icingaweb_client_keytab" "$icinga_username"
chgrp "$nginx_user" "$icingaweb_client_keytab"
chmod 640 "$icingaweb_client_keytab"
nginx_uid=$(id -u "$nginx_user")
install_directory -o "$nginx_user" -m 0700 "/var/krb5/user/${nginx_uid}"
ln -snfv "$icingaweb_client_keytab" "/var/krb5/user/${nginx_uid}/client.keytab"
# Create icinga postgres user and database.
postgres_create_role "$icinga_dbhost" "$icinga_username"
postgres_create_database "$icinga_dbhost" "$icinga_dbname" "$icinga_username"
# Apply icinga database schema.
if ! icinga_psql -c 'SELECT 1 FROM icingadb_schema'; then
icinga_psql -f /usr/local/share/examples/icingadb/schema/pgsql/schema.sql
fi
# Generate icinga database configuration.
install_template -g "${icinga_local_user}" -m 0640 "${icingadb_conf_dir}/config.yml"
# Create ZFS dataset for Redis DBs.
create_dataset -o "mountpoint=${redis_data_dir}" "${state_dataset}/redis"
install_directory -m 0700 -o "$redis_user" "$redis_data_dir"
# Generate redis configuration
install_template -m 0644 /usr/local/etc/redis.conf
# Add icinga user to redis group, so it can write to the redis unix socket.
pw groupmod "$redis_user" -m "$icinga_local_user"
# Generate icinga PKI.
install_directory -m 0700 -o "$icinga_local_user" -g "$icinga_local_user" \
"$icinga_cert_dir" \
"$icinga_ca_dir"
[ -f "${icinga_ca_dir}/ca.crt" ] \
|| icinga2 pki new-ca
[ -f "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.csr" ] \
|| icinga2 pki new-cert --cn "$BOXCONF_HOSTNAME" --key "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.key" --csr "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.csr"
[ -f "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.crt" ] \
|| icinga2 pki sign-csr --csr "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.csr" --cert "${icinga_cert_dir}/${BOXCONF_HOSTNAME}.crt"
ln -snfv "${icinga_ca_dir}/ca.crt" "${icinga_cert_dir}/ca.crt"
# Enable icinga modules.
for module in api icingadb notification; do
ln -snfv "../features-available/${module}.conf" "${icinga_conf_dir}/features-enabled/${module}.conf"
done
# Generate icinga configuration.
install_template -m 0640 -g "$icinga_local_user" \
"${icinga_conf_dir}/api-users.conf" \
"${icinga_conf_dir}/constants.conf" \
"${icinga_conf_dir}/icinga2.conf" \
"${icinga_conf_dir}/zones.conf" \
"${icinga_conf_dir}/features-available/icingadb.conf" \
"${icinga_conf_dir}/conf.d/users.conf" \
"${icinga_conf_dir}/conf.d/services.conf" \
"${icinga_conf_dir}/conf.d/notifications.conf" \
"${icinga_conf_dir}/conf.d/hosts.conf"
install_file -m 0640 -g "$icinga_local_user" \
"${icinga_conf_dir}/conf.d/app.conf" \
"${icinga_conf_dir}/conf.d/commands.conf" \
"${icinga_conf_dir}/conf.d/downtimes.conf" \
"${icinga_conf_dir}/conf.d/groups.conf" \
"${icinga_conf_dir}/conf.d/templates.conf" \
"${icinga_conf_dir}/conf.d/timeperiods.conf"
# Create icingaweb postgres user and database.
postgres_create_database "$icingaweb_dbhost" "$icingaweb_dbname" "$icinga_username"
# Apply icingaweb database schema.
if ! icingaweb_psql -c 'SELECT 1 FROM icingaweb_schema'; then
icingaweb_psql -f /usr/local/www/icingaweb2/schema/pgsql.schema.sql
fi
# Generate icingaweb configuration.
find "$icinga_conf_dir" -name '*.sample' -delete
install_directory -m 2770 -g "$nginx_user" \
"$icingaweb_conf_dir" \
"${icingaweb_conf_dir}/enabledModules" \
"${icingaweb_conf_dir}/modules" \
"${icingaweb_conf_dir}/modules/icingadb"
install_template -m 0660 -g "$nginx_user" \
"${icingaweb_conf_dir}/modules/icingadb/commandtransports.ini" \
"${icingaweb_conf_dir}/modules/icingadb/config.ini" \
"${icingaweb_conf_dir}/modules/icingadb/redis.ini" \
"${icingaweb_conf_dir}/config.ini" \
"${icingaweb_conf_dir}/resources.ini" \
"${icingaweb_conf_dir}/authentication.ini" \
"${icingaweb_conf_dir}/groups.ini" \
"${icingaweb_conf_dir}/roles.ini"
ln -snfv "${icingaweb_install_dir}/modules/icingadb" "${icingaweb_conf_dir}/enabledModules/icingadb"
# Generate nginx configuration.
install_file -m 0644 /usr/local/etc/nginx/fastcgi_params
install_template -m 0644 \
/usr/local/etc/nginx/nginx.conf \
/usr/local/etc/nginx/vhosts.conf
# Create HTTP service principal and keytab.
add_principal -nokey -x "containerdn=${services_basedn}" "HTTP/${fqdn}"
ktadd -k "$nginx_keytab" "HTTP/${fqdn}"
chgrp "$nginx_user" "$nginx_keytab"
chmod 640 "$nginx_keytab"
# Generate php-fpm configuration.
install_file -m 0644 \
/usr/local/etc/php.ini \
/usr/local/etc/php-fpm.conf
install_template -m 0644 \
/usr/local/etc/php-fpm.d/icingaweb.conf
> /usr/local/etc/php-fpm.d/www.conf
# Copy TLS certificate for nginx.
install_certificate nginx "$icingaweb_https_cert"
install_certificate_key nginx "$icingaweb_https_key"
# Icinga spawns a number of threads based on the core count of the machine. On machines
# with a large number of CPU cores, this can be undesirable (especially if run from a jail
# with cpuset()).
#
# The thread count can be overriden with the -DConcurrency=N argument to icinga2.
# Unfortunately, icinga2 rc script from ports does not have a way to override the
# daemon arguments. So we have to copy over a custom one ("myicinga2").
#
# https://icinga.com/docs/icinga-2/latest/doc/15-troubleshooting/#try-reducing-concurrency-threads
install_file -m 0555 /usr/local/etc/rc.d/myicinga2
# Enable and start daemons.
sysrc -v \
nginx_enable=YES \
php_fpm_enable=YES \
redis_enable=YES \
icingadb_enable=YES \
myicinga2_enable=YES \
icinga2_flags="-DConfiguration.Concurrency=${icinga_threads}"
service nginx restart
service php_fpm restart
service redis restart
service icingadb restart > /dev/null 2>&1
service myicinga2 restart
# Create icingaweb access role.
ldap_add "cn=${icingaweb_access_role},${roles_basedn}" <<EOF
objectClass: groupOfMembers
cn: ${icingaweb_access_role}
EOF
# Copy custom plugins.
install_file -m 0555 /usr/local/libexec/nagios/check_eapol
# Create wpa_supplicant file for radius checks.
install_template -m 0640 -g "$icinga_local_user" "${icinga_home_dir}/eap-ttls-pap.conf"
install_template -m 0640 -g "$icinga_local_user" "${icinga_home_dir}/eap-tls.conf"
# Add icinga user to wifi access role.
ldap_add "cn=${wifi_access_role},${roles_basedn}" <<EOF
objectClass: groupOfMembers
cn: ${wifi_access_role}
EOF
ldap_add_attribute "cn=${wifi_access_role},${roles_basedn}" member "$icinga_dn"
# Copy icinga client certificate.
install_certificate -g "$icinga_local_user" icinga "$icinga_tls_client_cert"
install_certificate_key -m 0640 -g "$icinga_local_user" icinga "$icinga_tls_client_key"
# Copy icinga ssh key.
install_directory -m 0755 -o "$icinga_local_user" -g "$icinga_local_user" "${icinga_home_dir}/.ssh"
install_directory -m 0700 -o "$icinga_local_user" -g "$icinga_local_user" "${icinga_home_dir}/.ssh/sockets"
install_file -m 0600 -o "$icinga_local_user" -g "$icinga_local_user" "${icinga_home_dir}/.ssh/id_ed25519"
# Generate ssh client configuration.
install_file -m 0600 -o "$icinga_local_user" -g "$icinga_local_user" "${icinga_home_dir}/.ssh/config"
|