diff options
author | Cullum Smith <cullum@sacredheartsc.com> | 2024-10-12 08:14:59 -0400 |
---|---|---|
committer | Cullum Smith <cullum@sacredheartsc.com> | 2024-10-12 08:15:33 -0400 |
commit | 99b8524c16cc99ceeaf1ebf588f2fc0f2c0fbe0a (patch) | |
tree | 3ffa4113f23eca6cea8ff2c94ba7ce60188d943e | |
parent | 1c882c769e5476b5cb3fa294257c76165a7a6f46 (diff) | |
download | infrastructure-99b8524c16cc99ceeaf1ebf588f2fc0f2c0fbe0a.tar.gz |
add a bunch of hostclasses
93 files changed, 2232 insertions, 42 deletions
diff --git a/files/etc/cron.d/davical.dav_server b/files/etc/cron.d/davical.dav_server new file mode 100644 index 0000000..73f0278 --- /dev/null +++ b/files/etc/cron.d/davical.dav_server @@ -0,0 +1,2 @@ +MAILTO=root +0,15,30,45 * * * * ${nginx_user} ${davical_repo_dir}/scripts/cron-sync-ldap.php ${fqdn} diff --git a/files/etc/cron.d/prosody.xmpp_server b/files/etc/cron.d/prosody.xmpp_server new file mode 100644 index 0000000..b95f010 --- /dev/null +++ b/files/etc/cron.d/prosody.xmpp_server @@ -0,0 +1,3 @@ +MAILTO=root +0 0 * * * * ${prosody_local_user} /usr/local/libexec/prosody-acme-proxy -q ${prosody_user}@${prosody_acme_host} ${prosody_domains} +0 0 * * * * ${prosody_local_user} /usr/local/libexec/prosody-update-roster ${prosody_access_role} > ${prosody_roster_path} diff --git a/files/etc/pam.d/znc.znc_server b/files/etc/pam.d/znc.znc_server new file mode 100644 index 0000000..6479aca --- /dev/null +++ b/files/etc/pam.d/znc.znc_server @@ -0,0 +1,2 @@ +auth required /usr/local/lib/pam_ldap.so +account required /usr/local/lib/pam_ldap.so diff --git a/files/usr/local/etc/asterisk/extensions.conf.asterisk_server b/files/usr/local/etc/asterisk/extensions.conf.asterisk_server new file mode 100644 index 0000000..301fe66 --- /dev/null +++ b/files/usr/local/etc/asterisk/extensions.conf.asterisk_server @@ -0,0 +1,5 @@ +[public] +exten => _X.,1,Hangup(3) + +[default] +exten => _X.,1,Hangup(3) diff --git a/files/usr/local/etc/asterisk/logger.conf.asterisk_server b/files/usr/local/etc/asterisk/logger.conf.asterisk_server new file mode 100644 index 0000000..3bf2a53 --- /dev/null +++ b/files/usr/local/etc/asterisk/logger.conf.asterisk_server @@ -0,0 +1,3 @@ +[logfiles] +console => notice,warning,error +syslog.daemon => notice,warning,error,security,verbose1 diff --git a/files/usr/local/etc/asterisk/pjsip.conf.asterisk_server b/files/usr/local/etc/asterisk/pjsip.conf.asterisk_server new file mode 100644 index 0000000..0f83a81 --- /dev/null +++ b/files/usr/local/etc/asterisk/pjsip.conf.asterisk_server @@ -0,0 +1,26 @@ +[transport-defaults](!) +type = transport +bind = 0.0.0.0 +local_net = 127.0.0.0/8 +local_net = 10.0.0.0/8 +local_net = 172.16.0.0/12 +local_net = 192.168.0.0/16 +external_media_address = ${asterisk_public_ip} +external_signaling_address = ${asterisk_public_ip} + +[transport-udp](transport-defaults) +protocol = udp + +[transport-tcp](transport-defaults) +protocol = tcp + +[transport-tls](transport-defaults) +protocol = tls +bind = 0.0.0.0:5061 +method = tlsv1_2 +cert_file = ${asterisk_public_tls_cert} +priv_key_file = ${asterisk_public_tls_key} +ca_list_file = ${ca_root_nss_bundle} +verify_client = no +verify_server = yes +allow_reload = yes diff --git a/files/usr/local/etc/asterisk/pjsip_wizard.conf.asterisk_server b/files/usr/local/etc/asterisk/pjsip_wizard.conf.asterisk_server new file mode 100644 index 0000000..1de448f --- /dev/null +++ b/files/usr/local/etc/asterisk/pjsip_wizard.conf.asterisk_server @@ -0,0 +1,65 @@ +;;;;;;;;;;; +; Trunks +;;;;;;;;;;; + +[trunk-defaults](!) +type = wizard +sends_auth = yes +sends_registrations = yes +endpoint/rtp_symmetric = yes +endpoint/rewrite_contact = yes +endpoint/send_rpid = yes +endpoint/from_domain = ${asterisk_sip_domain} +endpoint/allow = !all,ulaw +registration/max_retries = 4294967295 +registration/auth_rejection_permanent = no +aor/qualify_frequency = 30 + +$(for trunk in ${asterisk_trunks:-}; do + eval "trunk_proto=\${asterisk_trunk_${trunk}_proto:-'tcp'}" + eval "trunk_remote=\${asterisk_trunk_${trunk}_remote}" + eval "trunk_username=\${asterisk_trunk_${trunk}_username}" + eval "trunk_password=\${asterisk_trunk_${trunk}_password}" + eval "trunk_context=\${asterisk_trunk_${trunk}_context}" + echo "\ +[${trunk}](trunk-defaults) +transport = transport-${trunk_proto} +remote_hosts = ${trunk_remote} +endpoint/context = ${trunk_context} +endpoint/media_encryption = no +outbound_auth/username = ${trunk_username} +outbound_auth/password = ${trunk_password} +"; done) + + +[extension-defaults](!) +type = wizard +accepts_registrations = yes +accepts_auth = yes +aor/remove_existing = yes +endpoint/allow = !all,g722,ulaw +endpoint/from_domain = ${asterisk_sip_domain} +endpoint/subscribe_context = subscribe + +$(for ext in ${asterisk_exts:-}; do + eval "ext_context=\${asterisk_ext_${ext}_context}" + eval "ext_password=\${asterisk_ext_${ext}_password}" + eval "ext_max_contacts=\${asterisk_ext_${ext}_max_contacts:-1}" + eval "ext_qualify_freq=\${asterisk_ext_${ext}_qualify_freq:-30}" + eval "ext_qualify_timeout=\${asterisk_ext_${ext}_qualify_timeout:-3.0}" + eval "ext_direct_media=\${asterisk_ext_${ext}_direct_media:-yes}" + eval "ext_cid_name=\${asterisk_ext_${ext}_cid_name}" + eval "ext_cid_number=\${asterisk_ext_${ext}_cid_number:-$ext}" + eval "ext_mailbox=\${asterisk_ext_${ext}_mailbox:-$ext}" + echo "\ +[${ext}](extension-defaults) +endpoint/context = ${ext_context} +endpoint/mailboxes = ${ext_mailbox}@default +endpoint/callerid = ${ext_cid_name} <${ext_cid_number}> +inbound_auth/username = ${ext} +inbound_auth/password = ${ext_password} +aor/max_contacts = ${ext_max_contacts} +aor/qualify_frequency = ${ext_qualify_freq} +aor/qualify_timeout = ${ext_qualify_timeout} +endpoint/direct_media = ${ext_direct_media} +"; done) diff --git a/files/usr/local/etc/asterisk/queues.conf.asterisk_server b/files/usr/local/etc/asterisk/queues.conf.asterisk_server new file mode 100644 index 0000000..87b8ed4 --- /dev/null +++ b/files/usr/local/etc/asterisk/queues.conf.asterisk_server @@ -0,0 +1,31 @@ +[general] +persistentmembers = yes +autofill = yes +monitor-type = MixMonitor +shared_lastcall = yes +log_membername_as_agent = yes + +$(for queue in ${asterisk_queues:-}; do + eval "queue_strategy=\${asterisk_queue_${queue}_strategy}" + eval "queue_timeout=\${asterisk_queue_${queue}_timeout:-15}" + eval "queue_retry=\${asterisk_queue_${queue}_retry:-5}" + eval "queue_ringinuse=\${asterisk_queue_${queue}_ringinuse:-yes}" + eval "queue_members=\${asterisk_queue_${queue}_members}" + echo "\ +[${queue}] +strategy = ${queue_strategy} +timeout = ${queue_timeout} +retry = ${queue_retry} +timeoutpriority = app +announce-frequency = 0 +announce-holdtime = no +announce-position = no +periodic-announce-frequency = 0 +joinempty = yes +leavewhenempty = no +ringinuse = ${queue_ringinuse} +timeoutrestart = yes" +for member in $queue_members; do + eval "member_name=\${asterisk_ext_${member}_cid_name}" + echo "member => PJSIP/${member},0,${member_name},PJSIP/${member}" +done; done) diff --git a/files/usr/local/etc/asterisk/rtp.conf.asterisk_server b/files/usr/local/etc/asterisk/rtp.conf.asterisk_server new file mode 100644 index 0000000..d16d1f0 --- /dev/null +++ b/files/usr/local/etc/asterisk/rtp.conf.asterisk_server @@ -0,0 +1,3 @@ +[general] +rtpstart=${asterisk_rtp_start_port} +rtpend=${asterisk_rtp_end_port} diff --git a/files/usr/local/etc/asterisk/voicemail.conf.asterisk_server b/files/usr/local/etc/asterisk/voicemail.conf.asterisk_server new file mode 100644 index 0000000..c67559f --- /dev/null +++ b/files/usr/local/etc/asterisk/voicemail.conf.asterisk_server @@ -0,0 +1,31 @@ +[general] +format=wav49|gsm|wav + +serveremail=${asterisk_from_email} +attach=yes +maxmsg=100 +maxsecs=300 +maxgreet=60 +skipms=3000 +maxsilence=10 +silencethreshold=128 +maxlogins=3 + +emailsubject=New voicemail \${VM_MSGNUM} in mailbox \${VM_MAILBOX} +emailbody=Hi \${VM_NAME},\n\nYou have a new voicemail in mailbox \${VM_MAILBOX}.\n\nFrom: \${VM_CALLERID}\nDate: \${VM_DATE}\nDuration: \${VM_DUR}\nMessage Number: \${VM_MSGNUM} +emaildateformat=%A, %B %d, %Y at %r + +tz=myzone +locale=${asterisk_locale} +minpassword=4 + +[zonemessages] +myzone=${asterisk_timezone}|'vm-received' Q 'digits/at' IMp + +[default] +$(for mailbox in ${asterisk_mailboxes:-}; do + eval "mailbox_password=\${asterisk_mailbox_${mailbox}_password:-${asterisk_default_mailbox_password}}" + eval "mailbox_name=\${asterisk_mailbox_${mailbox}_name:-}" + eval "mailbox_email=\${asterisk_mailbox_${mailbox}_email:-}" + echo "${mailbox} => ${mailbox_password},${mailbox_name},${mailbox_email},,," +done) diff --git a/files/usr/local/etc/dovecot/rspamd.conf.sh.imap_server b/files/usr/local/etc/dovecot/rspamd.conf.sh.imap_server new file mode 100644 index 0000000..c1293e4 --- /dev/null +++ b/files/usr/local/etc/dovecot/rspamd.conf.sh.imap_server @@ -0,0 +1,5 @@ +#!/bin/sh + +RSPAMD_HOST="${rspamd_host}.${domain}" +RSPAMD_PASSWORD="${rspamd_rw_password}" +RSPAMD_KEY="${rspamd_pubkey}" diff --git a/files/usr/local/etc/nginx/fastcgi_params.common b/files/usr/local/etc/nginx/fastcgi_params.common new file mode 100644 index 0000000..d0a6c69 --- /dev/null +++ b/files/usr/local/etc/nginx/fastcgi_params.common @@ -0,0 +1,31 @@ +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param PATH_INFO $fastcgi_path_info; +fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; +fastcgi_param REQUEST_SCHEME $scheme; +fastcgi_param HTTPS $https if_not_empty; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $host; +fastcgi_param REMOTE_USER $remote_user if_not_empty; + +# PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; + +# Protect against HTTPoxy vuln +fastcgi_param HTTP_PROXY ""; diff --git a/files/usr/local/etc/nginx/nginx.conf.common b/files/usr/local/etc/nginx/nginx.conf.common index 1da7c3c..98ff9f9 100644 --- a/files/usr/local/etc/nginx/nginx.conf.common +++ b/files/usr/local/etc/nginx/nginx.conf.common @@ -33,8 +33,22 @@ http { ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; - ssl_protocols TLSv1.3; - ssl_prefer_server_ciphers off; +$(if [ "${nginx_public:-}" = true ]; then <<EOF + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; + ssl_dhparam ${dhparams_path}; + ssl_stapling on; + ssl_stapling_verify on; + resolver ${resolvers}; + resolver_timeout 5s; +EOF +else + cat <<EOF + ssl_protocols TLSv1.3; +EOF +fi +) + ssl_prefer_server_ciphers off; map \$http_upgrade \$connection_upgrade { default upgrade; @@ -47,10 +61,11 @@ $([ "${nginx_gssapi:-}" = true ] && cat <<EOF EOF ) -$([ "${acme:-}" = true ] && [ "${acme_standalone:-}" != true ] && cat <<EOF +$(if [ "${acme:-}" = true ] && [ "${acme_standalone:-}" != true ]; then +cat <<EOF server { - listen 0.0.0.0:80 default_server; - listen [::]:80 default_server; + listen 0.0.0.0:80; + listen [::]:80; location /.well-known/acme-challenge/ { root ${acme_webroot}; @@ -62,6 +77,18 @@ $([ "${acme:-}" = true ] && [ "${acme_standalone:-}" != true ] && cat <<EOF } } EOF + elif [ "${nginx_redirect:-}" != false ]; then +cat <<EOF + server { + listen 0.0.0.0:80; + listen [::]:80; + + location / { + return 301 https://\$host\$request_uri; + } + } +EOF + fi ) include vhosts.conf; diff --git a/files/usr/local/etc/nginx/vhosts.conf.bitwarden_server b/files/usr/local/etc/nginx/vhosts.conf.bitwarden_server new file mode 100644 index 0000000..0ef31bb --- /dev/null +++ b/files/usr/local/etc/nginx/vhosts.conf.bitwarden_server @@ -0,0 +1,36 @@ +upstream vaultwarden { + zone vaultwarden 64k; + server 127.0.0.1:${vaultwarden_port}; + keepalive 2; +} + +map \$http_upgrade \$connection_upgrade { + default upgrade; + '' ""; +} + +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + client_max_body_size 256M; + + ssl_certificate ${vaultwarden_https_cert}; + ssl_certificate_key ${vaultwarden_https_key}; + + add_header Strict-Transport-Security "max-age=63072000" always; + + location / { + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection \$connection_upgrade; + + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + + proxy_pass http://vaultwarden/; + } +} diff --git a/files/usr/local/etc/nginx/vhosts.conf.dav_server b/files/usr/local/etc/nginx/vhosts.conf.dav_server new file mode 100644 index 0000000..71bbc71 --- /dev/null +++ b/files/usr/local/etc/nginx/vhosts.conf.dav_server @@ -0,0 +1,55 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + root ${davical_webroot}; + index index.html index.php; + + ssl_certificate ${davical_https_cert}; + ssl_certificate_key ${davical_https_key}; + + add_header Strict-Transport-Security "max-age=63072000" always; + + auth_gss_keytab ${davical_keytab}; + auth_gss_allow_basic_fallback off; + + location / { + auth_gss on; + satisfy any; +$(printf ' deny %s;\n' $kerberized_cidrs) + allow all; + try_files \$uri \$uri/ /caldav.php\$uri?\$query_string; + } + + location /.well-known/ { + try_files \$uri \$uri/ /caldav.php\$uri?\$query_string; + } + + location ~ ^/caldav\.php/\.well-known/ { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + fastcgi_index index.php; + fastcgi_intercept_errors on; + include fastcgi_params; + fastcgi_pass unix:${davical_fpm_socket}; + } + + location ~ [^/]\.php(/|$) { + auth_gss on; + satisfy any; +$(printf ' deny %s;\n' $kerberized_cidrs) + allow all; + + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + fastcgi_index index.php; + fastcgi_intercept_errors on; + include fastcgi_params; + fastcgi_pass unix:${davical_fpm_socket}; + } +} diff --git a/files/usr/local/etc/nginx/vhosts.conf.smtp_server b/files/usr/local/etc/nginx/vhosts.conf.smtp_server index 4b84ede..322ca34 100644 --- a/files/usr/local/etc/nginx/vhosts.conf.smtp_server +++ b/files/usr/local/etc/nginx/vhosts.conf.smtp_server @@ -4,8 +4,8 @@ server { http2 on; - ssl_certificate ${rspamd_tls_cert}; - ssl_certificate_key ${rspamd_tls_key}; + ssl_certificate ${rspamd_https_cert}; + ssl_certificate_key ${rspamd_https_key}; add_header Strict-Transport-Security "max-age=63072000" always; diff --git a/files/usr/local/etc/nginx/vhosts.conf.ttrss_server b/files/usr/local/etc/nginx/vhosts.conf.ttrss_server new file mode 100644 index 0000000..fb0343d --- /dev/null +++ b/files/usr/local/etc/nginx/vhosts.conf.ttrss_server @@ -0,0 +1,43 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + root ${ttrss_repo_dir}; + index index.php index.html; + + ssl_certificate ${ttrss_https_cert}; + ssl_certificate_key ${ttrss_https_key}; + + add_header Strict-Transport-Security "max-age=63072000" always; + + auth_gss_keytab ${ttrss_keytab}; + auth_gss_allow_basic_fallback off; + + location ~ ^/index\.php$ { + auth_gss on; + satisfy any; +$(printf ' deny %s;\n' $kerberized_cidrs) + allow all; + + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + fastcgi_index index.php; + fastcgi_intercept_errors on; + include fastcgi_params; + fastcgi_pass unix:${ttrss_fpm_socket}; + } + + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + if (!-f \$document_root\$fastcgi_script_name) { + return 404; + } + fastcgi_index index.php; + fastcgi_intercept_errors on; + include fastcgi_params; + fastcgi_pass unix:${ttrss_fpm_socket}; + } +} diff --git a/files/usr/local/etc/nginx/vhosts.conf.xmpp_server b/files/usr/local/etc/nginx/vhosts.conf.xmpp_server new file mode 100644 index 0000000..732a6de --- /dev/null +++ b/files/usr/local/etc/nginx/vhosts.conf.xmpp_server @@ -0,0 +1,21 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + http2 on; + + ssl_certificate ${prosody_https_cert}; + ssl_certificate_key ${prosody_https_key}; + ssl_trusted_certificate ${prosody_https_cacert}; + + add_header Strict-Transport-Security "max-age=63072000" always; + + location / { + proxy_http_version 1.1; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + proxy_pass http://127.0.0.1:${prosody_http_port}; + } +} diff --git a/files/usr/local/etc/nginx/vhosts.conf.znc_server b/files/usr/local/etc/nginx/vhosts.conf.znc_server new file mode 100644 index 0000000..ee75878 --- /dev/null +++ b/files/usr/local/etc/nginx/vhosts.conf.znc_server @@ -0,0 +1,21 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + http2 on; + + ssl_certificate ${znc_tls_cert}; + ssl_certificate_key ${znc_tls_key}; + + add_header Strict-Transport-Security "max-age=63072000" always; + + location / { + proxy_http_version 1.1; + + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + + proxy_pass http://127.0.0.1:${znc_http_port}/; + } +} diff --git a/files/usr/local/etc/nsd/nsd.conf.authoritative_nameserver b/files/usr/local/etc/nsd/nsd.conf.authoritative_nameserver new file mode 100644 index 0000000..b6d1e11 --- /dev/null +++ b/files/usr/local/etc/nsd/nsd.conf.authoritative_nameserver @@ -0,0 +1,22 @@ +server: + server-count: ${nsd_threads} + log-only-syslog: yes + verbosity: 1 + hide-version: yes + minimal-responses: yes + refuse-any: yes +$(for zone in ${nsd_zones:-}; do + eval "zone_name=\${nsd_${zone}_domain}" + eval "zone_slaves=\${nsd_${zone}_slaves:-}" + echo "zone: + name: ${zone_name} + zonefile: ${nsd_conf_dir}/${zone_name}.zone" + for slave in $zone_slaves; do + echo " notify: ${slave} NOKEY" + echo " provide-xfr: ${slave} NOKEY" + done +done) + +remote-control: + control-enable: yes + control-interface: ${nsd_run_dir}/nsd.ctl diff --git a/files/usr/local/etc/nslcd.conf.common b/files/usr/local/etc/nslcd.conf.common index ca27337..9798ba9 100644 --- a/files/usr/local/etc/nslcd.conf.common +++ b/files/usr/local/etc/nslcd.conf.common @@ -12,3 +12,5 @@ sasl_mech GSSAPI nss_min_uid ${nslcd_min_uid} nss_initgroups_ignoreusers ALLLOCAL nss_nested_groups yes + +pam_authz_search (&(uid=\$username)(memberOf=cn=\$service-access,${roles_basedn})) diff --git a/files/usr/local/etc/openldap/ldap.conf.common b/files/usr/local/etc/openldap/ldap.conf.common index 2be3425..22b20bb 100644 --- a/files/usr/local/etc/openldap/ldap.conf.common +++ b/files/usr/local/etc/openldap/ldap.conf.common @@ -11,3 +11,4 @@ ACCOUNTS_BASE ${accounts_basedn} USERS_BASE ${users_basedn} GROUPS_BASE ${groups_basedn} HOSTS_BASE ${hosts_basedn} +ROLES_BASE ${roles_basedn} diff --git a/files/usr/local/etc/openldap/ldap.conf.idm_server b/files/usr/local/etc/openldap/ldap.conf.idm_server index 2e77244..4c7a929 100644 --- a/files/usr/local/etc/openldap/ldap.conf.idm_server +++ b/files/usr/local/etc/openldap/ldap.conf.idm_server @@ -11,3 +11,4 @@ ACCOUNTS_BASE ${accounts_basedn} USERS_BASE ${users_basedn} GROUPS_BASE ${groups_basedn} HOSTS_BASE ${hosts_basedn} +ROLES_BASE ${roles_basedn} diff --git a/files/usr/local/etc/php-fpm.conf.common b/files/usr/local/etc/php-fpm.conf.common new file mode 100644 index 0000000..e4c8f88 --- /dev/null +++ b/files/usr/local/etc/php-fpm.conf.common @@ -0,0 +1,4 @@ +[global] +pid = run/php-fpm.pid +error_log = syslog +include=/usr/local/etc/php-fpm.d/*.conf diff --git a/files/usr/local/etc/php-fpm.d/davical.conf.dav_server b/files/usr/local/etc/php-fpm.d/davical.conf.dav_server new file mode 100644 index 0000000..faf5f62 --- /dev/null +++ b/files/usr/local/etc/php-fpm.d/davical.conf.dav_server @@ -0,0 +1,20 @@ +[davical] +user = ${nginx_user} +group = ${nginx_user} + +listen = ${davical_fpm_socket} + +listen.owner = ${nginx_user} +listen.group = ${nginx_user} +listen.mode = 0660 + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 + +chdir = ${davical_webroot} + +catch_workers_output = yes +decorate_workers_output = no diff --git a/files/usr/local/etc/php-fpm.d/ttrss.conf.ttrss_server b/files/usr/local/etc/php-fpm.d/ttrss.conf.ttrss_server new file mode 100644 index 0000000..9519ab5 --- /dev/null +++ b/files/usr/local/etc/php-fpm.d/ttrss.conf.ttrss_server @@ -0,0 +1,23 @@ +[ttrss] +user = ${nginx_user} +group = ${nginx_user} + +listen = ${ttrss_fpm_socket} + +listen.owner = ${nginx_user} +listen.group = ${nginx_user} +listen.mode = 0660 + +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 + +chdir = ${ttrss_repo_dir} + +catch_workers_output = yes +decorate_workers_output = no + +; ttrss needs git to show its version info. +env["PATH"] = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin" diff --git a/files/usr/local/etc/php.ini.common b/files/usr/local/etc/php.ini.common new file mode 100644 index 0000000..40cfa9e --- /dev/null +++ b/files/usr/local/etc/php.ini.common @@ -0,0 +1,138 @@ +[PHP] +engine = On +short_open_tag = Off +precision = 14 +output_buffering = 4096 +zlib.output_compression = Off +implicit_flush = Off +unserialize_callback_func = +serialize_precision = -1 +disable_functions = +disable_classes = +zend.enable_gc = On +zend.exception_ignore_args = On +zend.exception_string_param_max_len = 0 +expose_php = On +max_execution_time = 30 +max_input_time = 60 +memory_limit = 128M +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT +display_errors = Off +display_startup_errors = Off +log_errors = On +ignore_repeated_errors = Off +ignore_repeated_source = Off +report_memleaks = On +html_errors = Off +error_log = syslog +syslog.ident = php +syslog.facility = user +variables_order = "GPCS" +request_order = "GP" +register_argc_argv = Off +auto_globals_jit = On +post_max_size = 8M +auto_prepend_file = +auto_append_file = +default_mimetype = "text/html" +default_charset = "UTF-8" +doc_root = +user_dir = +enable_dl = Off +file_uploads = On +upload_max_filesize = 2M +max_file_uploads = 20 +allow_url_fopen = On +allow_url_include = Off +default_socket_timeout = 60 + +[CLI Server] +cli_server.color = On + +[Date] +;date.timezone = + +[Pdo_mysql] +pdo_mysql.default_socket= + + +[mail function] +mail.add_x_header = Off +mail.mixed_lf_and_crlf = Off + +[ODBC] +odbc.allow_persistent = On +odbc.check_persistent = On +odbc.max_persistent = -1 +odbc.max_links = -1 +odbc.defaultlrl = 4096 +odbc.defaultbinmode = 1 + +[MySQLi] +mysqli.max_persistent = -1 +mysqli.allow_persistent = On +mysqli.max_links = -1 +mysqli.default_port = 3306 +mysqli.default_socket = +mysqli.default_host = +mysqli.default_user = +mysqli.default_pw = + +[mysqlnd] +mysqlnd.collect_statistics = On +mysqlnd.collect_memory_statistics = Off + + +[PostgreSQL] +pgsql.allow_persistent = On +pgsql.auto_reset_persistent = Off +pgsql.max_persistent = -1 +pgsql.max_links = -1 +pgsql.ignore_notice = 0 +pgsql.log_notice = 0 + +[bcmath] +bcmath.scale = 0 + +[browscap] + +[Session] +session.save_handler = files +session.use_strict_mode = 1 +session.use_cookies = 1 +session.use_only_cookies = 1 +session.name = PHPSESSID +session.auto_start = 0 +session.cookie_lifetime = 0 +session.cookie_path = / +session.cookie_domain = +session.cookie_httponly = +session.cookie_samesite = +session.serialize_handler = php +session.gc_probability = 1 +session.gc_divisor = 1000 +session.gc_maxlifetime = 1440 +session.referer_check = +session.cache_limiter = nocache +session.cache_expire = 180 +session.use_trans_sid = 0 +session.sid_length = 26 +session.trans_sid_tags = "a=href,area=href,frame=src,form=" +session.sid_bits_per_character = 5 + +[Assertion] +zend.assertions = -1 + + +[Tidy] +tidy.clean_output = Off + +[soap] +soap.wsdl_cache_enabled=1 +soap.wsdl_cache_dir="/tmp" +soap.wsdl_cache_ttl=86400 +soap.wsdl_cache_limit = 5 + +[opcache] +opcache.enable=1 +opcache.enable_cli=0 diff --git a/files/usr/local/etc/poudriere.d/pkglist.pkg_repository b/files/usr/local/etc/poudriere.d/pkglist.pkg_repository index d24ce06..848e558 100644 --- a/files/usr/local/etc/poudriere.d/pkglist.pkg_repository +++ b/files/usr/local/etc/poudriere.d/pkglist.pkg_repository @@ -1,4 +1,10 @@ +archivers/php${php_version}-phar +archivers/php${php_version}-zip converters/php${php_version}-iconv +converters/php${php_version}-mbstring +databases/luadbi +databases/p5-DBD-Pg +databases/p5-DBI databases/php${php_version}-pdo_pgsql databases/php${php_version}-pgsql databases/postgresql${postgresql_version}-client @@ -7,6 +13,9 @@ databases/redis devel/ccache devel/git@lite devel/php${php_version}-gettext +devel/php${php_version}-intl +devel/php${php_version}-pcntl +devel/php${php_version}-tokenizer dns/bind-tools dns/nsd dns/powerdns @@ -14,6 +23,10 @@ dns/unbound editors/vim@console editors/vim@tiny ftp/php${php_version}-curl +graphics/php${php_version}-exif +graphics/php${php_version}-gd +irc/znc +irc/znc-clientbuffer java/openjdk21 lang/python lang/php${php_version} @@ -25,6 +38,8 @@ mail/postfix mail/rspamd mail/sieve-connect misc/php${php_version}-calendar +net/asterisk18 +net/lualdap net/nss-pam-ldapd-sasl net/openldap26-client net/openldap26-server @@ -32,6 +47,10 @@ net/p5-perl-ldap net/php${php_version}-ldap net/py-python-ldap net/rsync +net/php${php_version}-sockets +net/turnserver +net-im/prosody +net-im/prosody-modules ports-mgmt/poudriere security/acme.sh security/cyrus-sasl2-saslauthd @@ -41,16 +60,25 @@ security/krb5@ldap security/openssh-portable security/pam_krb5@mit security/pam_mkhomedir +security/php${php_version}-filter security/sshpass security/sudo +security/vaultwarden sysutils/htop sysutils/lsof sysutils/p5-Sys-Syslog +sysutils/php${php_version}-fileinfo +sysutils/php${php_version}-posix sysutils/pwgen sysutils/stow sysutils/tmux sysutils/tree +textproc/p5-YAML +textproc/php${php_version}-ctype +textproc/php${php_version}-dom +textproc/php${php_version}-simplexml textproc/php${php_version}-xml +textproc/php${php_version}-xmlwriter www/nginx www/php${php_version}-opcache www/php${php_version}-session diff --git a/files/usr/local/etc/prosody/prosody.cfg.lua.xmpp_server b/files/usr/local/etc/prosody/prosody.cfg.lua.xmpp_server new file mode 100644 index 0000000..083a6ce --- /dev/null +++ b/files/usr/local/etc/prosody/prosody.cfg.lua.xmpp_server @@ -0,0 +1,106 @@ +$([ -n "${prosody_admins:-}" ] && echo "admins = { \"$(join '", "' $prosody_admins)\" }") +pidfile = "/var/run/prosody/prosody.pid" + +plugin_paths = { "/usr/local/lib/prosody-modules" } + +modules_enabled = { + + -- Generally required + "disco"; -- Service discovery + "roster"; -- Allow users to have a roster. Recommended ;) + "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. + "tls"; -- Add support for secure TLS on c2s/s2s connections + + -- Not essential, but recommended + "blocklist"; -- Allow users to block communications with other users + "bookmarks"; -- Synchronise the list of open rooms between clients + "carbons"; -- Keep multiple online clients in sync + "dialback"; -- Support for verifying remote servers using DNS + "limits"; -- Enable bandwidth limiting for XMPP connections + "pep"; -- Allow users to store public and private data in their account + "private"; -- Legacy account storage mechanism (XEP-0049) + "smacks"; -- Stream management and resumption (XEP-0198) + "vcard4"; -- User profiles (stored in PEP) + "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard + + -- Nice to have + "ping"; -- Replies to XMPP pings with pongs + "register"; -- Allow users to register on this server using a client and change passwords + "time"; -- Let others know the time here on this server + "uptime"; -- Report how long server has been running + "version"; -- Replies to server version requests + "mam"; -- Store recent messages to allow multi-device synchronization + "turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls + + -- Admin interfaces + "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands + "admin_shell"; -- Allow secure administration via 'prosodyctl shell' + + -- Other specific functionality + "groups"; -- Shared roster support + "csi_battery_saver"; + "reload_modules"; +} + +reload_modules = { "groups", "tls" } + +groups_file = "${prosody_roster_path}" + +s2s_secure_auth = true + +limits = { + c2s = { + rate = "10kb/s"; + }; + s2sin = { + rate = "30kb/s"; + }; +} + +authentication = "ldap" +ldap_server = "${ldap_hosts}" +ldap_tls = true +ldap_base = "${users_basedn}" +ldap_scope = "subtree" +ldap_filter = "(&(memberOf=cn=${prosody_access_role},${roles_basedn})(mailAddress=\$user@\$host))" +ldap_rootdn = "${prosody_dn}" +ldap_password = "${prosody_ldap_password}" + +storage = "sql" +sql = { driver = "PostgreSQL", database = "${prosody_dbname}", username = "${prosody_username}", host = "${prosody_dbhost}" } + +archive_expires_after = "${prosody_archive_expiration}" + +turn_external_host = "${prosody_turn_host}" +turn_external_port = ${prosody_turn_port} +turn_external_secret = "${prosody_turn_secret}" + +log = { + info = "*syslog"; +} + +certificates = "certs" + +http_ports = { ${prosody_http_port} } +http_interfaces = { "127.0.0.1" } +https_interfaces = { } +https_ports = { } +http_external_url = "https://${prosody_public_fqdn}/" +https_external_url = "https://${prosody_public_fqdn}/" +trusted_proxies = { "127.0.0.1" } +http_max_content_size = ${prosody_upload_sizelimit} + +Component "${prosody_public_fqdn}" "http_upload" +http_upload_file_size_limit = ${prosody_upload_sizelimit} +http_upload_expire_after = ${prosody_upload_expiration} +http_upload_quota = ${prosody_upload_quota} + +$(for vhost in $prosody_domains; do cat <<EOF +VirtualHost "${vhost}" + disco_items = { + { "${prosody_public_fqdn}" } + } +Component "conference.${vhost}" "muc" + modules_enabled = { "muc_mam"} +EOF +done) diff --git a/files/usr/local/etc/rc.conf.d/vaultwarden.bitwarden_server b/files/usr/local/etc/rc.conf.d/vaultwarden.bitwarden_server new file mode 100644 index 0000000..a0923d6 --- /dev/null +++ b/files/usr/local/etc/rc.conf.d/vaultwarden.bitwarden_server @@ -0,0 +1,19 @@ +export ROCKET_ADDRESS=127.0.0.1 +export ROCKET_PORT="${vaultwarden_port}" +export ROCKET_CLI_COLORS=false +export LOG_LEVEL=warn +export EXTENDED_LOGGING=true +export IP_HEADER=X-Forwarded-For + +export DATABASE_URL="postgresql://${vaultwarden_username}@${vaultwarden_dbhost}/${vaultwarden_dbname}" + +export SIGNUPS_ALLOWED=true +export SIGNUPS_VERIFY=true + +export INVITATIONS_ALLOWED=false + +export DOMAIN="https://${vaultwarden_fqdn}" + +export USE_SENDMAIL=true +export SMTP_FROM="bitwarden-noreply@${email_domain}" +export SMTP_FROM_NAME=Bitwarden diff --git a/files/usr/local/etc/rc.d/ttrssd.ttrss_server b/files/usr/local/etc/rc.d/ttrssd.ttrss_server new file mode 100644 index 0000000..d04fa3d --- /dev/null +++ b/files/usr/local/etc/rc.d/ttrssd.ttrss_server @@ -0,0 +1,47 @@ +#!/bin/sh + +# PROVIDE: ttrssd +# REQUIRE: NETWORKING kstart +# KEYWORD: shutdown + +. /etc/rc.subr + +name='ttrssd' +rcvar='ttrssd_enable' + +load_rc_config "$name" +: ${ttrssd_enable='NO'} +: ${ttrssd_webroot='/usr/local/www/tt-rss'} +: ${ttrssd_user='www'} +: ${ttrssd_syslog_priority:='info'} +: ${ttrssd_syslog_facility:='daemon'} + +ttrssd_syslog_tag=$name +ttrssd_chdir=$ttrssd_webroot + +pidfile="/var/run/${name}/${name}.pid" +procname=/usr/local/bin/php + +command=/usr/sbin/daemon +command_args="-f \ +-s ${ttrssd_syslog_priority} \ +-l ${ttrssd_syslog_facility} \ +-T ${ttrssd_syslog_tag} \ +-p ${pidfile} \ +-t ${name} \ +/usr/local/bin/php \ +-d syslog.ident=${ttrssd_syslog_tag} \ +-d syslog.facility=${ttrssd_syslog_facility} \ +${ttrssd_webroot}/update_daemon2.php" + +required_files="${ttrssd_webroot}/config.php" +start_precmd=ttrssd_prestart + +ttrssd_prestart(){ + install -d -m 0755 -o ${ttrssd_user} "/var/run/${name}" +} + +# ttrss needs git to show its version info. +PATH='/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin' + +run_rc_command "$1" diff --git a/files/usr/local/etc/ssh/sshd_config.d/acmeproxy.conf.common b/files/usr/local/etc/ssh/sshd_config.d/acmeproxy.conf.common new file mode 100644 index 0000000..63022e3 --- /dev/null +++ b/files/usr/local/etc/ssh/sshd_config.d/acmeproxy.conf.common @@ -0,0 +1,11 @@ +Match Group ${acmeproxy_client_group} + ChrootDirectory ${acmeproxy_home} + ForceCommand internal-sftp -R + DisableForwarding yes + PermitUserRC no + PermitTTY no + GSSAPIAuthentication yes + KbdInteractiveAuthentication no + PasswordAuthentication no + PubkeyAuthentication no + AuthenticationMethods gssapi-with-mic diff --git a/files/usr/local/etc/ssh/sshd_config.freebsd b/files/usr/local/etc/ssh/sshd_config.freebsd index 52d9bfe..eca2276 100644 --- a/files/usr/local/etc/ssh/sshd_config.freebsd +++ b/files/usr/local/etc/ssh/sshd_config.freebsd @@ -1,4 +1,4 @@ -Include /etc/ssh/sshd_config.d/*.conf +Include /usr/local/etc/ssh/sshd_config.d/*.conf PermitRootLogin prohibit-password AuthorizedKeysFile .ssh/authorized_keys diff --git a/files/usr/local/etc/sudoers.d/acme.asterisk_server b/files/usr/local/etc/sudoers.d/acme.asterisk_server new file mode 100644 index 0000000..6ca9cd6 --- /dev/null +++ b/files/usr/local/etc/sudoers.d/acme.asterisk_server @@ -0,0 +1 @@ +${acme_user} ALL=(root) NOPASSWD: /usr/sbin/service asterisk reload diff --git a/files/usr/local/etc/sudoers.d/acme.public_webserver b/files/usr/local/etc/sudoers.d/acme.public_webserver new file mode 100644 index 0000000..9ca89b8 --- /dev/null +++ b/files/usr/local/etc/sudoers.d/acme.public_webserver @@ -0,0 +1 @@ +${acme_user} ALL=(root) NOPASSWD: /usr/sbin/service nginx reload diff --git a/files/usr/local/etc/sudoers.d/acme.smtp_server b/files/usr/local/etc/sudoers.d/acme.smtp_server index 5180fdc..4e8c381 100644 --- a/files/usr/local/etc/sudoers.d/acme.smtp_server +++ b/files/usr/local/etc/sudoers.d/acme.smtp_server @@ -1 +1 @@ -acme ALL=(root) NOPASSWD: /usr/sbin/service postfix reload +${acme_user} ALL=(root) NOPASSWD: /usr/sbin/service postfix reload diff --git a/files/usr/local/etc/sudoers.d/acme.xmpp_server b/files/usr/local/etc/sudoers.d/acme.xmpp_server new file mode 100644 index 0000000..9ca89b8 --- /dev/null +++ b/files/usr/local/etc/sudoers.d/acme.xmpp_server @@ -0,0 +1 @@ +${acme_user} ALL=(root) NOPASSWD: /usr/sbin/service nginx reload diff --git a/files/usr/local/etc/turnserver.conf.turn_server b/files/usr/local/etc/turnserver.conf.turn_server new file mode 100644 index 0000000..dc62883 --- /dev/null +++ b/files/usr/local/etc/turnserver.conf.turn_server @@ -0,0 +1,61 @@ +relay-threads=${coturn_threads} +listening-port=${coturn_listen_port} +tls-listening-port=0 + +listening-ip=${BOXCONF_DEFAULT_IPV4} +relay-ip=${BOXCONF_DEFAULT_IPV4} +external-ip=${coturn_external_ip} + +min-port=${coturn_min_port} +max-port=${coturn_max_port} + +verbose + +use-auth-secret +static-auth-secret=${coturn_secret} + +realm=${coturn_realm} + +no-tls +no-dtls + +syslog + +no-software-attribute +no-multicast-peers + +denied-peer-ip=0.0.0.0-0.255.255.255 +denied-peer-ip=10.0.0.0-10.255.255.255 +denied-peer-ip=100.64.0.0-100.127.255.255 +denied-peer-ip=127.0.0.0-127.255.255.255 +denied-peer-ip=169.254.0.0-169.254.255.255 +denied-peer-ip=172.16.0.0-172.31.255.255 +denied-peer-ip=192.0.0.0-192.0.0.255 +denied-peer-ip=192.0.2.0-192.0.2.255 +denied-peer-ip=192.88.99.0-192.88.99.255 +denied-peer-ip=192.168.0.0-192.168.255.255 +denied-peer-ip=198.18.0.0-198.19.255.255 +denied-peer-ip=198.51.100.0-198.51.100.255 +denied-peer-ip=203.0.113.0-203.0.113.255 +denied-peer-ip=240.0.0.0-255.255.255.255 +denied-peer-ip=::1 +denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff +denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255 +denied-peer-ip=100::-100::ffff:ffff:ffff:ffff +denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff +denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff +denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff + +secure-stun + +# You can't drop privileges here, due to a FreeBSD issue with SO_REUSEPORT: +# https://github.com/coturn/coturn/issues/1098 +# Do this in /etc/rc.conf instead. +#proc-user=coturn +#proc-group=coturn + +no-cli +no-rfc5780 +no-stun-backward-compatibility +response-origin-only-with-rfc5780 diff --git a/files/usr/local/etc/znc/configs/znc.conf.znc_server b/files/usr/local/etc/znc/configs/znc.conf.znc_server new file mode 100644 index 0000000..487db8e --- /dev/null +++ b/files/usr/local/etc/znc/configs/znc.conf.znc_server @@ -0,0 +1,55 @@ +LoadModule = cyrusauth saslauthd +LoadModule = webadmin +LoadModule = corecaps +SSLCertFile = ${znc_tls_cert} +SSLKeyFile = ${znc_tls_key} +Version = 1.9.0 + +<Listener web> + AllowIRC = false + AllowWeb = true + IPv4 = true + IPv6 = false + Host = 127.0.0.1 + Port = ${znc_http_port} + SSL = false +</Listener> + +<Listener irc> + AllowIRC = true + AllowWeb = false + IPv4 = true + IPv6 = true + Port = ${znc_irc_port} + SSL = true +</Listener> + +<User admin> + Admin = true + Nick = znc_admin + AltNick = znc_admin_ + Ident = znc_admin + RealName = ZNC Administrator + + <Pass password> + Hash = :: + Method = MD5 + Salt = :: + </Pass> +</User> + +<User ${znc_clone_user}> + Admin = false + Nick = znc_user + AltNick = znc_user_ + Ident = znc_user + RealName = ZNC User + MaxNetworks = ${znc_max_networks} + LoadModule = chansaver + + <Pass password> + Hash = :: + Method = MD5 + Salt = :: + </Pass> +</User> diff --git a/files/usr/local/etc/znc/moddata/cyrusauth/.registry.znc_server b/files/usr/local/etc/znc/moddata/cyrusauth/.registry.znc_server new file mode 100644 index 0000000..539fee0 --- /dev/null +++ b/files/usr/local/etc/znc/moddata/cyrusauth/.registry.znc_server @@ -0,0 +1,2 @@ +CloneUser ${znc_clone_user} +CreateUser yes diff --git a/files/usr/local/lib/sasl2/znc.conf.znc_server b/files/usr/local/lib/sasl2/znc.conf.znc_server new file mode 100644 index 0000000..f272cc7 --- /dev/null +++ b/files/usr/local/lib/sasl2/znc.conf.znc_server @@ -0,0 +1,3 @@ +mech_list: plain login +pwcheck_method: saslauthd +saslauthd_path: ${saslauthd_runtime_dir}/mux diff --git a/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server b/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server index e09674a..b5b0d2d 100644 --- a/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server +++ b/files/usr/local/libexec/dovecot/sieve-pipe/report-ham.sh.imap_server @@ -1,7 +1,11 @@ #!/bin/sh -exec /usr/local/bin/rspamc \\ - --connect="${rspamd_host}.${domain}" \\ - --password="${rspamd_rw_password}" \\ - --key="${rspamd_pubkey}" \\ +set -e + +. /usr/local/etc/dovecot/rspamd.conf.sh + +exec /usr/local/bin/rspamc \ + --connect="$RSPAMD_HOST" \ + --password="$RSPAMD_PASSWORD" \ + --key="$RSPAMD_KEY" \ learn_ham diff --git a/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server b/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server index 825113f..ec46319 100644 --- a/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server +++ b/files/usr/local/libexec/dovecot/sieve-pipe/report-spam.sh.imap_server @@ -1,7 +1,11 @@ #!/bin/sh -exec /usr/local/bin/rspamc \\ - --connect="${rspamd_host}.${domain}" \\ - --password="${rspamd_rw_password}" \\ - --key="${rspamd_pubkey}" \\ +set -e + +. /usr/local/etc/dovecot/rspamd.conf.sh + +exec /usr/local/bin/rspamc \ + --connect="$RSPAMD_HOST" \ + --password="$RSPAMD_PASSWORD" \ + --key="$RSPAMD_KEY" \ learn_spam diff --git a/files/usr/local/libexec/idm-ssh-authorized-keys.common b/files/usr/local/libexec/idm-ssh-authorized-keys.common index 89d2f20..ef7ba3c 100644 --- a/files/usr/local/libexec/idm-ssh-authorized-keys.common +++ b/files/usr/local/libexec/idm-ssh-authorized-keys.common @@ -7,7 +7,7 @@ use Net::LDAP; use Net::LDAP::Util qw(escape_filter_value); use Authen::SASL; -open my $fh, '<', '/usr/local/etc/openldap/ldap.conf' or quit($!); +open my $fh, '<', '/usr/local/etc/openldap/ldap.conf' or die($!); my %config; while (<$fh>) { chomp; @@ -18,9 +18,9 @@ while (<$fh>) { } close($fh); -my $mech = $config{SASL_MECH} // 'GSSAPI'; -my $uri = $config{URI} // quit('URI not specified'); -my $basedn = $config{USERS_BASE} // quit('USERS_BASE not specified'); +my $mech = $config{SASL_MECH} // 'GSSAPI'; +my $uri = $config{URI} // die("URI not specified\n"); +my $basedn = $config{USERS_BASE} // die("USERS_BASE not specified\n"); @ARGV == 1 or die "usage: $0 USERNAME\n"; my $username = $ARGV[0]; diff --git a/files/usr/local/libexec/idm-ssh-known-hosts.common b/files/usr/local/libexec/idm-ssh-known-hosts.common index 5b784d6..3bbcf65 100644 --- a/files/usr/local/libexec/idm-ssh-known-hosts.common +++ b/files/usr/local/libexec/idm-ssh-known-hosts.common @@ -29,8 +29,8 @@ while (<$fh>) { } close($fh); -my $mech = $config{SASL_MECH} // 'GSSAPI'; -my $uri = $config{URI} // quit('URI not specified'); +my $mech = $config{SASL_MECH} // 'GSSAPI'; +my $uri = $config{URI} // quit('URI not specified'); my $basedn = $config{HOSTS_BASE} // quit('HOSTS_BASE not specified'); my $conn = Net::LDAP->new($uri, version => '3') or quit($@); diff --git a/files/usr/local/libexec/prosody-acme-proxy.xmpp_server b/files/usr/local/libexec/prosody-acme-proxy.xmpp_server new file mode 100644 index 0000000..d69017b --- /dev/null +++ b/files/usr/local/libexec/prosody-acme-proxy.xmpp_server @@ -0,0 +1,54 @@ +#!/bin/sh + +# Retrieves ACME certificates from a different host over SFTP. +# Reloads prosody if any certificates were changed. + +set -eu -o pipefail + +PROSODY_USER=prosody +CERT_DIR=/usr/local/etc/prosody/certs +CHECKSUM_FILE="${CERT_DIR}/certs.md5" + +prog=$(basename "$(readlink -f "$0")") +usage="${prog} [-q] USER@TARGET_HOST DOMAIN..." + +usage(){ + printf 'usage: %s\n' "$usage" 1>&2 + exit 2 +} + +while getopts hq opt; do + case $opt in + h) usage ;; + q) exec 1>/dev/null ;; + esac +done +shift $((OPTIND - 1)) + +[ $# -ge 2 ] || usage +acmeproxy_target=$1; shift + +# Get md5 of any existing certificates. +touch "$CHECKSUM_FILE" +md5_old=$(cat "$CHECKSUM_FILE") + +# Retrieve certs from the proxy host via SFTP. +{ printf 'lcd %s\n' "$CERT_DIR" + printf 'get certs/%s.crt\n' "$@" + printf 'get certs/%s.key\n' "$@" + printf 'quit\n' +} | sftp -b - "$acmeproxy_target" + +# Get md5 of the new certificates. +md5_new=$(md5sum "$CERT_DIR"/*.crt "$CERT_DIR"/*.key | tee "$CHECKSUM_FILE") + +# If any certificates differ, reload prosody. +if [ "$md5_old" != "$md5_new" ]; then + if prosodyctl status >/dev/null 2>&1; then + prosodyctl reload + else + echo 'prosody not running, not reloading' + fi +else + echo 'certificates unchanged' +fi diff --git a/files/usr/local/libexec/prosody-update-roster.xmpp_server b/files/usr/local/libexec/prosody-update-roster.xmpp_server new file mode 100644 index 0000000..1b79747 --- /dev/null +++ b/files/usr/local/libexec/prosody-update-roster.xmpp_server @@ -0,0 +1,47 @@ +#!/usr/local/bin/perl + +use strict; +use warnings; + +use Net::LDAP; +use Authen::SASL; + +@ARGV == 1 or die "usage: $0 ROLE_NAME\n"; +my $role = $ARGV[0]; + +open my $fh, '<', '/usr/local/etc/openldap/ldap.conf' or quit($!); +my %config; +while (<$fh>) { + chomp; + next if /^#/; + my @pair = split(' ', $_, 2); + next unless (@pair == 2); + $config{$pair[0]} = $pair[1]; +} +close($fh); + +my $mech = $config{SASL_MECH} // 'GSSAPI'; +my $uri = $config{URI} // die("URI not specified\n"); +my $users_basedn = $config{USERS_BASE} // die("USERS_BASE not specified\n"); +my $roles_basedn = $config{ROLES_BASE} // die("ROLES_BASE not specified\n"); + +my $conn = Net::LDAP->new($ldap_uris, version => '3') or die "$@"; +my $sasl = Authen::SASL->new($mech); +my $status = $conn->bind(sasl => $sasl); +$status->code and die $status->error; + +my $search = $conn->search( + scope => 'sub', + base => $users_basedn, + filter => "(&(memberOf=cn=$role,$roles_basedn)(mailAddress=*))", + attrs => ['mailAddress', 'cn']); + +print "[Internal]\n"; + +foreach my $entry ($search->entries) { + my $jid = ($entry->get_value('mailAddress'))[0]; + my $cn = ($entry->get_value('cn'))[0] // $jid; + print "$jid=$cn\n"; +} + +system('prosodyctl reload'); diff --git a/files/usr/local/www/davical/config/administration.yml.dav_server b/files/usr/local/www/davical/config/administration.yml.dav_server new file mode 100644 index 0000000..fdd5da2 --- /dev/null +++ b/files/usr/local/www/davical/config/administration.yml.dav_server @@ -0,0 +1,4 @@ +admin_db_user: ${boxconf_username} +admin_db_host: ${davical_dbhost} +admin_db_name: ${davical_dbname} +app_db_user: '"${davical_username}"' diff --git a/files/usr/local/www/davical/config/config.php.dav_server b/files/usr/local/www/davical/config/config.php.dav_server new file mode 100644 index 0000000..ec2cb26 --- /dev/null +++ b/files/usr/local/www/davical/config/config.php.dav_server @@ -0,0 +1,49 @@ +<?php +\$c->pg_connect[] = 'dbname=${davical_dbname} user=${davical_username} host=${davical_dbhost}'; +\$c->admin_email = '${davical_admin_email}'; + +\$c->restrict_setup_to_admin = true; + +\$c->home_calendar_name = 'calendar'; +\$c->home_addressbook_name = 'addressbook'; +\$c->default_privileges = array('read-free-busy', 'schedule-deliver'); +\$c->external_refresh = 60; +\$c->default_locale = 'en'; +\$c->allow_get_email_visibility = true; + +\$c->trust_x_forwarded = true; + +\$c->authenticate_hook['call'] = 'LDAP_check'; +\$c->authenticate_hook['config'] = array( + 'uri' => '${ldap_uri}', + 'host' => '${ldap_hosts}', + 'port' => '389', + 'sasl' => 'yes', + 'sasl_mech' => 'GSSAPI', + 'baseDNUsers' => '${users_basedn}', + 'baseDNGroups' => '${groups_basedn}', + 'scope' => 'onelevel', + 'protocolVersion' => 3, + 'optReferrals' => 0, + 'filterUsers' => '(memberOf=cn=${davical_access_role},${roles_basedn})', + 'filterGroups' => '(objectclass=groupOfMembers)', + 'mapping_field' => array('username' => 'uid', + 'modified' => 'modifyTimestamp', + 'fullname' => 'cn', + 'email' => 'mailAddress'), + 'group_mapping_field' => array('name' => 'cn', + 'fullname' => 'cn', + 'modified' => 'modifyTimestamp', + 'email' => 'mailAddress', + 'members' => 'member'), + 'group_member_dnfix' => true, + 'default_value' => array('date_format_type' => 'I','locale' => 'en'), + 'format_updated' => array('Y' => array(0,4), + 'm' => array(4,2), + 'd' => array(6,2), + 'H' => array(8,2), + 'M' => array(10,2), + 'S' => array(12,2)), + 'i_use_mode_kerberos' => 'i_know_what_i_am_doing', +); +include_once('drivers_ldap.php'); diff --git a/files/usr/local/www/tt-rss/config.php.ttrss_server b/files/usr/local/www/tt-rss/config.php.ttrss_server new file mode 100644 index 0000000..3598ef2 --- /dev/null +++ b/files/usr/local/www/tt-rss/config.php.ttrss_server @@ -0,0 +1,28 @@ +<?php +putenv('TTRSS_DB_TYPE=pgsql'); +putenv('TTRSS_DB_HOST=${ttrss_dbhost}'); +putenv('TTRSS_DB_USER=${ttrss_username}'); +putenv('TTRSS_DB_NAME=${ttrss_dbname}'); + +putenv('TTRSS_SELF_URL_PATH=https://${ttrss_fqdn}/'); +putenv('TTRSS_PHP_EXECUTABLE=/usr/local/bin/php'); + +putenv('TTRSS_SESSION_COOKIE_LIFETIME=604800'); + +putenv('TTRSS_SMTP_FROM_NAME=Tiny Tiny RSS'); +putenv('TTRSS_SMTP_FROM_ADDRESS=${ttrss_mail_from}'); + +putenv('TTRSS_CHECK_FOR_UPDATES=false'); +putenv('TTRSS_CHECK_FOR_PLUGIN_UPDATES=false'); +putenv('TTRSS_ENABLE_PLUGIN_INSTALLER=false'); +putenv('TTRSS_ENABLE_GZIP_OUTPUT=false'); +putenv('TTRSS_PLUGINS=auth_idm'); + +putenv('TTRSS_LOG_DESTINATION=syslog'); + +putenv('TTRSS_AUTH_IDM_URI=${ldap_uri}'); +putenv('TTRSS_AUTH_IDM_STARTTLS=false'); +putenv('TTRSS_AUTH_IDM_BASEDN=${users_basedn}'); +putenv('TTRSS_AUTH_IDM_SCOPE=sub'); +putenv('TTRSS_AUTH_IDM_FILTER=(memberOf=cn=${ttrss_access_role},${roles_basedn})'); +putenv('TTRSS_AUTH_IDM_ADMIN_FILTER=(memberOf=cn=${ttrss_admin_role},${roles_basedn})'); diff --git a/files/usr/local/www/tt-rss/plugins.local/auth_idm/init.php.ttrss_server b/files/usr/local/www/tt-rss/plugins.local/auth_idm/init.php.ttrss_server new file mode 100644 index 0000000..c025026 --- /dev/null +++ b/files/usr/local/www/tt-rss/plugins.local/auth_idm/init.php.ttrss_server @@ -0,0 +1,177 @@ +<?php +/** + * The following options may be specified in config.php: + * + * putenv('TTRSS_AUTH_IDM_URI=ldap://ldap.idm.example.com'); + * putenv('TTRSS_AUTH_IDM_BASEDN=ou=users,dc=idm,dc=example,dc=com'); + * putenv('TTRSS_AUTH_IDM_FILTER=(memberOf=cn=ttrss-users,ou=groups,dc=idm,dc=example,dc=com)'); + * putenv('TTRSS_AUTH_IDM_ADMIN_FILTER=(memberOf=cn=ttrss-admins,ou=groups,dc=idm,dc=example,dc=com)'); + * putenv('TTRSS_AUTH_IDM_FULLNAME_ATTRIBUTE=cn'); + * putenv('TTRSS_AUTH_IDM_EMAIL_ATTRIBUTE=mail'); + */ + +class Auth_Idm extends Auth_Base { + + const AUTH_IDM_URI = 'AUTH_IDM_URI'; + const AUTH_IDM_STARTTLS = 'AUTH_IDM_STARTTLS'; + const AUTH_IDM_BASEDN = 'AUTH_IDM_BASEDN'; + const AUTH_IDM_SCOPE = 'AUTH_IDM_SCOPE'; + const AUTH_IDM_FILTER = 'AUTH_IDM_FILTER'; + const AUTH_IDM_ADMIN_FILTER = 'AUTH_IDM_ADMIN_FILTER'; + const AUTH_IDM_USERNAME_ATTR = 'AUTH_IDM_USERNAME_ATTRIBUTE'; + const AUTH_IDM_FULLNAME_ATTR = 'AUTH_IDM_FULLNAME_ATTRIBUTE'; + const AUTH_IDM_EMAIL_ATTR = 'AUTH_IDM_EMAIL_ATTRIBUTE'; + + function about() { + return array(null, + 'Authenticates against REMOTE_USER variable and LDAP server', + 'cullum@sacredheartsc.com', + true); + } + + function init($host) { + $host->add_hook($host::HOOK_AUTH_USER, $this); + + Config::add(self::AUTH_IDM_URI, '', Config::T_STRING); + Config::add(self::AUTH_IDM_STARTTLS, false, Config::T_BOOL); + Config::add(self::AUTH_IDM_BASEDN, '', Config::T_STRING); + Config::add(self::AUTH_IDM_SCOPE, 'sub', Config::T_STRING); + Config::add(self::AUTH_IDM_FILTER, '', Config::T_STRING); + Config::add(self::AUTH_IDM_ADMIN_FILTER, '', Config::T_STRING); + Config::add(self::AUTH_IDM_USERNAME_ATTR, 'uid', Config::T_STRING); + Config::add(self::AUTH_IDM_FULLNAME_ATTR, 'cn', Config::T_STRING); + Config::add(self::AUTH_IDM_EMAIL_ATTR, 'mail', Config::T_STRING); + } + + private function ldap_get_user($username, $filter = null) { + switch ($this->scope) { + case 'sub': + $searchfunc = 'ldap_search'; break; + case 'one': + $searchfunc = 'ldap_list'; break; + case 'base': + $searchfunc = 'ldap_read'; break; + default: + Logger::log(E_USER_ERROR, "auth_idm: invalid search scope: $scope"); + return null; + } + + $uid_filter = '(' + . ldap_escape($this->username_attr, '', LDAP_ESCAPE_FILTER) + . '=' + . ldap_escape($username, '', LDAP_ESCAPE_FILTER) + . ')'; + + if (empty($filter)) { + $filter = $uid_filter; + } else { + $filter = "(&$filter$uid_filter)"; + } + + $results = $searchfunc($this->conn, $this->basedn, $filter, [$this->fullname_attr, $this->email_attr]); + if ($results && ldap_count_entries($this->conn, $results) == 1) { + if ($entry = ldap_first_entry($this->conn, $results)) { + if ($dn = ldap_get_dn($this->conn, $entry)) { + if ($attrs = ldap_get_attributes($this->conn, $entry)) { + return array( + 'dn' => $dn, + 'email' => $attrs[$this->email_attr][0], + 'fullname' => $attrs[$this->fullname_attr][0] + ); + } + } + } + } + return null; + } + + function authenticate($username = null, $password = null, $service = '') { + $this->basedn = Config::get(self::AUTH_IDM_BASEDN); + $this->scope = Config::get(self::AUTH_IDM_SCOPE); + $this->username_attr = Config::get(self::AUTH_IDM_USERNAME_ATTR); + $this->fullname_attr = Config::get(self::AUTH_IDM_FULLNAME_ATTR); + $this->email_attr = Config::get(self::AUTH_IDM_EMAIL_ATTR); + $uri = Config::get(self::AUTH_IDM_URI); + $starttls = Config::get(self::AUTH_IDM_STARTTLS); + $filter = Config::get(self::AUTH_IDM_FILTER); + $admin_filter = Config::get(self::AUTH_IDM_ADMIN_FILTER); + + // Get ldap connection handle. + if (!$this->conn = ldap_connect($uri)) { + return false; + } + + // Set protocol version 3. + if (!ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3)) { + return false; + } + + // Bind using kerberos credentials from the environment. + if (!ldap_sasl_bind($this->conn, null, null, 'GSSAPI')) { + return false; + } + + // Initiate STARTTLS (if requested) + if ($starttls and !ldap_start_tls($this->conn)) { + return false; + } + + // If REMOTE_USER was set by the webserver, use that. + if (!empty($_SERVER['REMOTE_USER'])) { + $username = $_SERVER['REMOTE_USER']; + } elseif (empty($username)) { + return false; + } + + $is_admin = false; + $user = null; + + // First, check if the ADIN_FILTER matches (if set). + if (!empty($admin_filter)) { + $user = $this->ldap_get_user($username, $admin_filter); + isset($user) && $is_admin = true; + } + + // If ADMIN_FILTER didn't match, try FILTER. + if (!isset($user)) { + $user = $this->ldap_get_user($username, $filter); + } + + // If no matching user from LDAP, reject. + if (!isset($user)) { + return false; + } + + // If webserver didn't validate the password, try an LDAP bind with the provided creds. + if (empty($_SERVER['REMOTE_USER']) and !ldap_bind($this->conn, $user['dn'], $password)) { + return false; + } + + // Get the TTRSS internal user ID. + if (!($userid = $this->auto_create_user($username))) { + return false; + } + + // Populate user details using the LDAP attributes. + if (Config::get(Config::AUTH_AUTO_CREATE)) { + if (!empty($user['fullname'])) { + $sth = $this->pdo->prepare('UPDATE ttrss_users SET full_name = ? WHERE id = ?'); + $sth->execute([$user['fullname'], $userid]); + } + + if (!empty($user['email'])) { + $sth = $this->pdo->prepare('UPDATE ttrss_users SET email = ? WHERE id = ?'); + $sth->execute([$user['email'], $userid]); + } + + $sth = $this->pdo->prepare('UPDATE ttrss_users SET access_level = ? WHERE id = ?'); + $sth->execute([$is_admin ? 10 : 0, $userid]); + } + + return $userid; + } + + function api_version() { + return 2; + } +} diff --git a/files/var/db/postgres/data16/postgresql.conf.postgresql_server b/files/var/db/postgres/data16/postgresql.conf.postgresql_server index e95104f..55874e7 100644 --- a/files/var/db/postgres/data16/postgresql.conf.postgresql_server +++ b/files/var/db/postgres/data16/postgresql.conf.postgresql_server @@ -5,7 +5,7 @@ krb_server_keyfile = 'FILE:${postgres_keytab}' krb_caseins_users = on ssl = on -ssl_ca_file = '${ca_cert}' +ssl_ca_file = '${site_cacert_path}' ssl_cert_file = '${postgres_tls_cert}' ssl_key_file = '${postgres_tls_key}' ssl_min_protocol_version = 'TLSv1.3' diff --git a/lib/60-ldap b/lib/60-ldap index d262849..249fed0 100644 --- a/lib/60-ldap +++ b/lib/60-ldap @@ -11,7 +11,7 @@ ldap_add(){ if [ "${BOXCONF_LDAP_SASL:-}" = true ]; then ldapadd -Q "$@" else - ldapadd -ZZ -D "$boxconf_dn" -w "$boxconf_password" "$@" + ldapadd -ZZ -x -D "$boxconf_dn" -w "$boxconf_password" "$@" fi } fi @@ -25,7 +25,7 @@ ldap_modify(){ if [ "${BOXCONF_LDAP_SASL:-}" = true ]; then ldapmodify -Q "$@" else - ldapmodify -ZZ -D "$boxconf_dn" -w "$boxconf_password" "$@" + ldapmodify -ZZ -x -D "$boxconf_dn" -w "$boxconf_password" "$@" fi } } @@ -36,7 +36,7 @@ ldap_delete(){ if [ "${BOXCONF_LDAP_SASL:-}" = true ]; then ldapdelete -Q "$@" else - ldapdelete -ZZ -D "$boxconf_dn" -w "$boxconf_password" "$@" + ldapdelete -ZZ -x -D "$boxconf_dn" -w "$boxconf_password" "$@" fi } @@ -46,7 +46,7 @@ ldap_search(){ if [ "${BOXCONF_LDAP_SASL:-}" = true ]; then ldapsearch -QLLL "$@" else - ldapsearch -o ldif_wrap=no -LLLZZ -D "$boxconf_dn" -w "$boxconf_password" "$@" + ldapsearch -o ldif_wrap=no -x -LLLZZ -D "$boxconf_dn" -w "$boxconf_password" "$@" fi } @@ -86,3 +86,13 @@ ldap_dn_exists(){ # $1 = DN ldap_search -s base -b "$1" dn > /dev/null 2>&1 } + +ldap_passwd(){ + # Set the userPassword attribute on a DN. + # $1 = DN, $2 = password + if [ "${BOXCONF_LDAP_SASL:-}" = true ]; then + ldappasswd -Q -s "$2" "$1" + else + ldappasswd -ZZ -x -D "$boxconf_dn" -w "$boxconf_password" -s "$2" "$1" + fi +} diff --git a/lib/60-postgres b/lib/60-postgres new file mode 100644 index 0000000..af37c27 --- /dev/null +++ b/lib/60-postgres @@ -0,0 +1,24 @@ +#!/bin/sh + +postgres_run(){ + PGSSLMODE=require PGPASSWORD="$boxconf_password" psql \ + --no-align \ + --echo-all \ + --tuples-only \ + --username="$boxconf_username" \ + -v ON_ERROR_STOP=1 \ + "$@" +} +postgres_create_role(){ + # $1 = postgres_host, $2 = username + cat <<EOF | postgres_run -h "${1}" -d postgres +SELECT 'CREATE ROLE "${2}" WITH LOGIN' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${2}')\\gexec +EOF +} + +postgres_create_database(){ + # $1 = postgres_host, $2 = dbname, $3 = owner + cat <<EOF | postgres_run -h "${1}" -d postgres +SELECT 'CREATE DATABASE "${2}" OWNER "${3:-postgres}"' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${2}')\\gexec +EOF +} diff --git a/scripts/common/10-vars b/scripts/common/10-vars index 6ea7cad..cae4496 100644 --- a/scripts/common/10-vars +++ b/scripts/common/10-vars @@ -12,6 +12,7 @@ idm_hostnames=$(echo "$idm_server_list" | awk '{print $1}') fqdn="${BOXCONF_HOSTNAME}.${domain}" : ${smtp_host:="smtp.${domain}"} +: ${postgres_host:="postgres.${domain}"} realm=$(echo "$domain" | tr '[:lower:]' '[:upper:]') diff --git a/scripts/hostclass/asterisk_server b/scripts/hostclass/asterisk_server new file mode 100644 index 0000000..d519730 --- /dev/null +++ b/scripts/hostclass/asterisk_server @@ -0,0 +1,74 @@ +#!/bin/sh + +: ${asterisk_public_fqdn:='pbx.example.com'} +: ${asterisk_public_ip:="$BOXCONF_DEFAULT_IPV4"} +: ${asterisk_from_email:="asterisk-noreply@${email_domain}"} +: ${asterisk_sip_domain:="${email_domain}"} +: ${asterisk_locale:='en_US.UTF-8'} +: ${asterisk_timezone:='America/New_York'} +: ${asterisk_default_mailbox_password:='1234'} + +# asterisk_mailboxes='1001 1002' +# asterisk_mailbox_1001_name='John Doe' +# asterisk_mailbox_1001_email='johndoe@example.com' +# +# asterisk_trunks='upstream1 upstream2' +# asterisk_trunk_upstream1_username=myusername +# asterisk_trunk_upstream1_password=changeme +# asterisk_trunk_upstream1_context=from-pstn +# asterisk_trunk_upstream1_proto=tcp +# asterisk_trunk_upstream1_remote='server.example.com:5060' +# +# asterisk_exts='1001 1002' +# asterisk_ext_1001_password=changeme +# asterisk_ext_1001_context=from-internal +# asterisk_ext_1001_mailbox=1001 +# asterisk_ext_1001_cid_name='Bob Office' +# +# asterisk_queues=home +# asterisk_queue_home_stragegy=ringall +# asterisk_queue_home_timeout=30 +# asterisk_queue_home_retry=1 +# asterisk_queue_home_members='1001 1002' + +asterisk_public_tls_cert="${acme_cert_dir}/asterisk.crt" +asterisk_public_tls_key="${acme_cert_dir}/asterisk.key" +asterisk_conf_dir=/usr/local/etc/asterisk +asterisk_db_dir=/var/db/asterisk +asterisk_user=asterisk + +# Install packages. +pkg install -y \ + asterisk18 \ + ca_root_nss + +# Create ZFS dataset for Asterisk DB. +create_dataset -o "mountpoint=${asterisk_db_dir}" "${state_dataset}/asterisk" +install_directory -o "$asterisk_user" -g "$asterisk_user" -m 0755 "$asterisk_db_dir" + +# Generate asterisk configuration. +install_file -m 0644 \ + "${asterisk_conf_dir}/extensions.conf" \ + "${asterisk_conf_dir}/logger.conf" \ + "${asterisk_conf_dir}/queues.conf" \ + "${asterisk_conf_dir}/voicemail.conf" + +install_template -m 0644 \ + "${asterisk_conf_dir}/voicemail.conf" \ + "${asterisk_conf_dir}/pjsip.conf" \ + "${asterisk_conf_dir}/rtp.conf" + +install_template -m 0640 \ + "${asterisk_conf_dir}/pjsip_wizard.conf" + +# Acquire public TLS certificate. +install_template -m 0600 /usr/local/etc/sudoers.d/acme +acme_install_certificate \ + -c "$asterisk_public_tls_cert" \ + -k "$asterisk_public_tls_key" \ + -r 'sudo service asterisk reload' \ + "$asterisk_public_fqdn" + +# Enable and start asterisk. +sysrc -v asterisk_enable=YES +service asterisk restart diff --git a/scripts/hostclass/authoritative_nameserver b/scripts/hostclass/authoritative_nameserver new file mode 100644 index 0000000..69a7dde --- /dev/null +++ b/scripts/hostclass/authoritative_nameserver @@ -0,0 +1,27 @@ +#!/bin/sh + +: ${nsd_zones:=''} +: ${nsd_threads:='2'} + +# nsd_zones='example1 example2' +# nsd_example1_domain=example.com +# nsd_example1_slaves='1.2.3.4 5.6.7.8' + +nsd_conf_dir=/usr/local/etc/nsd +nsd_run_dir=/var/run/nsd + +# Install packages. +pkg install -y nsd + +# Generate nsd configuration. +install_template -m 0644 /usr/local/etc/nsd/nsd.conf + +# Copy zone files. +for zone in $nsd_zones; do + eval "zone_name=\${nsd_${zone}_zone}" + install_file -m 0644 "${nsd_conf_dir}/${zone_name}.zone" +done + +# Enable and start nsd. +sysrc -v nsd_enable=YES +service nsd restart diff --git a/scripts/hostclass/bitwarden_server b/scripts/hostclass/bitwarden_server new file mode 100644 index 0000000..5e19bdd --- /dev/null +++ b/scripts/hostclass/bitwarden_server @@ -0,0 +1,58 @@ +#!/bin/sh + +: ${vaultwarden_username:='s-vaultwarden'} +: ${vaultwarden_dbname:='vaultwarden'} +: ${vaultwarden_dbhost:="$postgres_host"} +: ${vaultwarden_fqdn:="$fqdn"} + +vaultwarden_local_username=$nginx_user +vaultwarden_uid=$(id -u "$vaultwarden_local_username") +vaultwarden_https_cert="${nginx_conf_dir}/vaultwarden.crt" +vaultwarden_https_key="${nginx_conf_dir}/vaultwarden.key" +vaultwarden_home=/usr/local/www/vaultwarden +vaultwarden_port=8080 +vaultwarden_client_keytab="${keytab_dir}/vaultwarden.client.keytab" + +pkg install -y \ + vaultwarden \ + nginx + +# Create vaultwarden principal and keytab. +add_principal -nokey -x "containerdn=${robots_basedn}" "$vaultwarden_username" + +ktadd -k "$vaultwarden_client_keytab" "$vaultwarden_username" +chgrp "$vaultwarden_local_username" "$vaultwarden_client_keytab" +chmod 640 "$vaultwarden_client_keytab" + +install_directory -o "$vaultwarden_local_username" -m 0700 "/var/krb5/user/${vaultwarden_uid}" +ln -snfv "$vaultwarden_client_keytab" "/var/krb5/user/${vaultwarden_uid}/client.keytab" + +# Create postgres user and database. +postgres_create_role "$vaultwarden_dbhost" "$vaultwarden_username" +postgres_create_database "$vaultwarden_dbhost" "$vaultwarden_dbname" "$vaultwarden_username" + +# Generate vaultwarden configuration. +install_template -m 0644 /usr/local/etc/rc.conf.d/vaultwarden + +# Copy TLS certificate for nginx. +install_certificate nginx "$vaultwarden_https_cert" +install_certificate_key nginx "$vaultwarden_https_key" + +# Generate nginx configuration. +install_template -m 0644 \ + /usr/local/etc/nginx/nginx.conf \ + /usr/local/etc/nginx/vhosts.conf + +# Enable and start daemons. +sysrc -v \ + vaultwarden_enable=YES \ + vaultwarden_user="$vaultwarden_local_username" \ + vaultwarden_group="$vaultwarden_local_username" \ + nginx_enable=YES \ + +service nginx restart + +# The vaultwarden rc script seems to hold onto open descriptors, which causes +# the parent boxconf SSH process to never close. +echo 'Restarting vaultwarden.' +service vaultwarden restart > /dev/null 2>&1 < /dev/null diff --git a/scripts/hostclass/dav_server b/scripts/hostclass/dav_server new file mode 100644 index 0000000..b7391bd --- /dev/null +++ b/scripts/hostclass/dav_server @@ -0,0 +1,139 @@ +#!/bin/sh + +: ${davical_username:='s-davical'} +: ${davical_dbname:='davical'} +: ${davical_dbhost:="$postgres_host"} +: ${davical_admin_email:="$root_mail_alias"} +: ${davical_access_role:='dav-access'} +: ${davical_repo:='https://gitlab.com/davical-project/davical.git'} +: ${davical_branch:='master'} +: ${davical_awl_repo:='https://gitlab.com/davical-project/awl.git'} +: ${davical_awl_branch:='master'} + +davical_repo_dir=/usr/local/www/davical +davical_awl_repo_dir=/usr/local/share/awl +davical_webroot="${davical_repo_dir}/htdocs" + +davical_https_cert="${nginx_conf_dir}/davical.crt" +davical_https_key="${nginx_conf_dir}/davical.key" +davical_https_cacert="${nginx_conf_dir}/davical.ca.crt" +davical_keytab="${keytab_dir}/davical.keytab" +davical_client_keytab="${keytab_dir}/davical.client.keytab" +davical_fpm_socket=/var/run/fpm-davical.sock + +davical_psql(){ + postgres_run --host="$davical_dbhost" --dbname="$davical_dbname" "$@" +} + +# Install required packages. +pkg install -y \ + git-lite \ + nginx \ + php${php_version} \ + php${php_version}-calendar \ + php${php_version}-curl \ + php${php_version}-gettext \ + php${php_version}-iconv \ + php${php_version}-ldap \ + php${php_version}-opcache \ + php${php_version}-pdo_pgsql \ + php${php_version}-pgsql \ + php${php_version}-session \ + php${php_version}-xml \ + p5-DBD-Pg \ + p5-DBI \ + p5-YAML + +# Install davical from git. +[ -d "$davical_repo_dir" ] || git clone "$davical_repo" "$davical_repo_dir" +[ -d "$davical_awl_repo_dir" ] || git clone "$davical_awl_repo" "$davical_awl_repo_dir" + +# Update git repos. +git -C "$davical_repo_dir" pull --ff-only +git -C "$davical_repo_dir" switch "$davical_branch" +git -C "$davical_awl_repo_dir" pull --ff-only +git -C "$davical_awl_repo_dir" switch "$davical_awl_branch" + +# Create davical principal and keytab. +add_principal -nokey -x "containerdn=${robots_basedn}" "$davical_username" + +ktadd -k "$davical_client_keytab" "$davical_username" +chgrp "$nginx_user" "$davical_client_keytab" +chmod 640 "$davical_client_keytab" + +nginx_uid=$(id -u "$nginx_user") +install_directory -o "$nginx_user" -m 0700 "/var/krb5/user/${nginx_uid}" +ln -snfv "$davical_client_keytab" "/var/krb5/user/${nginx_uid}/client.keytab" + +# Create HTTP principal and keytab. +add_principal -nokey -x "containerdn=${services_basedn}" "HTTP/${fqdn}" + +ktadd -k "$davical_keytab" "HTTP/${fqdn}" +chgrp "$nginx_user" "$davical_keytab" +chmod 640 "$davical_keytab" + +ln -snfv "$davical_keytab" "/var/krb5/user/${nginx_uid}/keytab" + +# Generate davical configuration. +install_template -m 0644 \ + "${davical_repo_dir}/config/config.php" \ + "${davical_repo_dir}/config/administration.yml" + +# Create postgres user and database. +postgres_create_role "$davical_dbhost" "$davical_username" +postgres_create_database "$davical_dbhost" "$davical_dbname" + +# Initialize davical database. +if ! davical_psql -c 'SELECT 1 FROM awl_db_revision'; then + davical_psql \ + -f "${davical_awl_repo_dir}/dba/awl-tables.sql" \ + -f "${davical_awl_repo_dir}/dba/schema-management.sql" \ + -f "${davical_repo_dir}/dba/davical.sql" + + PGPASSWORD="$boxconf_password" PGSSLMODE=require \ + "${davical_repo_dir}/dba/update-davical-database" --debug --nopatch + + davical_psql -f "${davical_repo_dir}/dba/base-data.sql" + + PGPASSWORD="$boxconf_password" PGSSLMODE=require \ + "${davical_repo_dir}/dba/update-davical-database" --debug + + davical_psql -c "delete from usr where username = 'admin'" +fi + +# Copy TLS certificate for nginx. +install_certificate nginx "$davical_https_cert" +install_certificate_key nginx "$davical_https_key" + +# Generate nginx configuration. +install_file -m 0644 "${nginx_conf_dir}/fastcgi_params" +install_template -m 0644 \ + "${nginx_conf_dir}/nginx.conf" \ + "${nginx_conf_dir}/vhosts.conf" + +# 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/davical.conf +> /usr/local/etc/php-fpm.d/www.conf + +# Enable and start daemons. +sysrc -v \ + nginx_enable=YES \ + php_fpm_enable=YES +service nginx restart +service php_fpm restart + +# Sync groups from LDAP. +su -m "$nginx_user" -c "${davical_repo_dir}/scripts/cron-sync-ldap.php ${fqdn}" + +# Create cron job for keeping LDAP groups up-to-date. +install_template -m 0644 /etc/cron.d/davical + +# Create access role. +ldap_add "cn=${davical_access_role},${roles_basedn}" <<EOF +objectClass: groupOfMembers +cn: ${davical_access_role} +EOF diff --git a/scripts/hostclass/imap_server/30-dovecot b/scripts/hostclass/imap_server/30-dovecot index 07c089e..ff41da5 100644 --- a/scripts/hostclass/imap_server/30-dovecot +++ b/scripts/hostclass/imap_server/30-dovecot @@ -75,9 +75,10 @@ install_template -m 0644 \ "${dovecot_conf_dir}/conf.d/90-sieve-extprograms.conf" \ "${dovecot_conf_dir}/conf.d/auth-ldap.conf.ext" -install_template -m 0550 -o root -g "$dovecot_user" \ +install_template -m 0640 -o root -g "$dovecot_user" "${dovecot_conf_dir}/rspamd.conf.sh" +install_file -m 0555 \ "${dovecot_sieve_pipe_bin_dir}/report-spam.sh" \ - "${dovecot_sieve_pipe_bin_dir}/report-ham.sh" \ + "${dovecot_sieve_pipe_bin_dir}/report-ham.sh" install_file -m 0555 \ "${dovecot_script_dir}/quota-warning.sh" diff --git a/scripts/hostclass/postgresql_server b/scripts/hostclass/postgresql_server index a09c9f4..fb0ddcd 100644 --- a/scripts/hostclass/postgresql_server +++ b/scripts/hostclass/postgresql_server @@ -1,5 +1,7 @@ #!/bin/sh +# PostgreSQL jails need allow.sysvipc=1. + : ${postgres_max_connections:='128'} : ${postgres_shared_buffers:="$(( memsize / 2 ))"} : ${postgres_work_mem:="$(( memsize / 4 / ${postgres_max_connections} ))"} @@ -9,7 +11,7 @@ postgres_user=postgres postgres_home=/var/db/postgres -postgres_data_dir="${postgres_home}/data${postgres_version}" +postgres_data_dir="${postgres_home}/data${postgresql_version}" postgres_tls_cert="${postgres_home}/postgres.crt" postgres_tls_key="${postgres_home}/postgres.key" postgres_keytab="${keytab_dir}/postgres.keytab" @@ -67,8 +69,8 @@ service postgresql restart > /dev/null 2>&1 < /dev/null psql -c "DO \$$ BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${boxconf_user}') THEN - CREATE ROLE \"${boxconf_user}\" WITH LOGIN SUPERUSER; + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${boxconf_username}') THEN + CREATE ROLE \"${boxconf_username}\" WITH LOGIN SUPERUSER; END IF; END \$$" diff --git a/scripts/hostclass/public_webserver b/scripts/hostclass/public_webserver new file mode 100644 index 0000000..ccf5991 --- /dev/null +++ b/scripts/hostclass/public_webserver @@ -0,0 +1,42 @@ +#!/bin/sh + +# acme_certs='site1 site2' +# acme_site1_domains='example.net example.com' + +: ${acme_certs:=''} + +vhosts_dir=/usr/local/www + +# Install packages. +pkg install -y \ + nginx \ + rsync + +# Create ZFS dataset for webroots. +create_dataset -o "mountpoint=${vhosts_dir}" "${state_dataset}/vhosts" + +# Configure nginx. +install_template -m 0644 /usr/local/etc/nginx/nginx.conf +install -Cv -m 0644 /dev/null /usr/local/etc/nginx/vhosts.conf +sysrc -v nginx_enable=YES +service nginx restart + +# Acquire public TLS certificates. +install_template -m 0600 /usr/local/etc/sudoers.d/acme +for cert in $acme_certs; do + eval "acme_domains=\${acme_${cert}_domains}" + acme_install_certificate \ + -C "${acme_cert_dir}/${cert}.ca.crt" \ + -c "${acme_cert_dir}/${cert}.crt" \ + -k "${acme_cert_dir}/${cert}.key" \ + -g "$nginx_user" \ + -r 'sudo service nginx reload' \ + $acme_domains +done + +# Now that we have the ACME certs, add the vhosts. +install_template -m 0644 /usr/local/etc/nginx/vhosts.conf +service nginx restart + +# If any acmeproxy_domains were specified, setup the SFTP proxy. +acme_setup_proxy diff --git a/scripts/hostclass/smtp_server/10-rspamd b/scripts/hostclass/smtp_server/10-rspamd index 094dc8a..1794e04 100644 --- a/scripts/hostclass/smtp_server/10-rspamd +++ b/scripts/hostclass/smtp_server/10-rspamd @@ -21,8 +21,8 @@ rspamd_redis_sock=/var/run/redis/rspamd.sock rspamd_bayes_redis_sock=/var/run/redis/rspamd-bayes.sock rspamd_redis_data_dir="${redis_data_dir}/rspamd" rspamd_bayes_redis_data_dir="${redis_data_dir}/rspamd-bayes" -rspamd_tls_cert=/usr/local/etc/nginx/rspamd.crt -rspamd_tls_key=/usr/local/etc/nginx/rspamd.key +rspamd_https_cert="${nginx_conf_dir}/rspamd.crt" +rspamd_https_key="${nginx_conf_dir}/rspamd.key" nginx_keytab="${keytab_dir}/nginx.keytab" pkg install -y \ @@ -97,8 +97,8 @@ chgrp "$nginx_user" "$nginx_keytab" chmod 640 "$nginx_keytab" # Copy TLS certificate for nginx. -install_certificate nginx "$rspamd_tls_cert" -install_certificate_key nginx "$rspamd_tls_key" +install_certificate nginx "$rspamd_https_cert" +install_certificate_key nginx "$rspamd_https_key" # Enable and start rspamd and nginx. sysrc -v \ diff --git a/scripts/hostclass/smtp_server/20-postfix b/scripts/hostclass/smtp_server/20-postfix index e224e9b..68ac474 100644 --- a/scripts/hostclass/smtp_server/20-postfix +++ b/scripts/hostclass/smtp_server/20-postfix @@ -52,7 +52,7 @@ install_certificate_key -m 0640 -o root -g "$postfix_user" postfix "$postfix_loc if [ "$postfix_public_fqdn" != "$fqdn" ]; then # Acquire public TLS certificate. - install_file /usr/local/etc/sudoers.d/acme + install_template -m 0600 /usr/local/etc/sudoers.d/acme acme_install_certificate \ -c "$postfix_public_tls_cert" \ -k "$postfix_public_tls_key" \ diff --git a/scripts/hostclass/ttrss_server b/scripts/hostclass/ttrss_server new file mode 100644 index 0000000..1a2104a --- /dev/null +++ b/scripts/hostclass/ttrss_server @@ -0,0 +1,137 @@ +#!/bin/sh + +: ${ttrss_username:='s-ttrss'} +: ${ttrss_dbname:='ttrss'} +: ${ttrss_dbhost:="$postgres_host"} +: ${ttrss_fqdn:="$fqdn"} +: ${ttrss_access_role:='ttrss-access'} +: ${ttrss_admin_role:='ttrss-admin'} +: ${ttrss_mail_from:="ttrss-noreply@${email_domain}"} + +ttrss_https_cert="${nginx_conf_dir}/ttrss.crt" +ttrss_https_key="${nginx_conf_dir}/ttrss.key" +ttrss_repo='https://git.tt-rss.org/fox/tt-rss.git/' +ttrss_branch=master +ttrss_repo_dir=/usr/local/www/tt-rss +ttrss_keytab="${keytab_dir}/ttrss.keytab" +ttrss_client_keytab="${keytab_dir}/ttrss.client.keytab" +ttrss_fpm_socket=/var/run/fpm-ttrss.sock + +# Install required packages. +pkg install -y \ + ca_root_nss \ + nginx \ + git-lite \ + php${php_version}-ctype \ + php${php_version}-curl \ + php${php_version}-dom \ + php${php_version}-exif \ + php${php_version}-fileinfo \ + php${php_version}-filter \ + php${php_version}-gd \ + php${php_version}-iconv \ + php${php_version}-intl \ + php${php_version}-ldap \ + php${php_version}-mbstring \ + php${php_version}-opcache \ + php${php_version}-pcntl \ + php${php_version}-pdo \ + php${php_version}-pdo_pgsql \ + php${php_version}-pgsql \ + php${php_version}-phar \ + php${php_version}-posix \ + php${php_version}-session \ + php${php_version}-simplexml \ + php${php_version}-sockets \ + php${php_version}-tokenizer \ + php${php_version}-xml \ + php${php_version}-xmlwriter \ + php${php_version}-zip + +# Create ttrss principal and keytab. +add_principal -nokey -x "containerdn=${robots_basedn}" "$ttrss_username" + +ktadd -k "$ttrss_client_keytab" "$ttrss_username" +chgrp "$nginx_user" "$ttrss_client_keytab" +chmod 640 "$ttrss_client_keytab" + +nginx_uid=$(id -u "$nginx_user") +install_directory -o "$nginx_user" -m 0700 "/var/krb5/user/${nginx_uid}" +ln -snfv "$ttrss_client_keytab" "/var/krb5/user/${nginx_uid}/client.keytab" + +# Create HTTP principal and keytab. +add_principal -nokey -x "containerdn=${services_basedn}" "HTTP/${fqdn}" + +ktadd -k "$ttrss_keytab" "HTTP/${fqdn}" +chgrp "$nginx_user" "$ttrss_keytab" +chmod 640 "$ttrss_keytab" + +ln -snfv "$ttrss_keytab" "/var/krb5/user/${nginx_uid}/keytab" + +# Install ttrss from git. +[ -d "$ttrss_repo_dir" ] || git clone "$ttrss_repo" "$ttrss_repo_dir" + +# Update git repos. +git -C "$ttrss_repo_dir" pull --ff-only +git -C "$ttrss_repo_dir" switch "$ttrss_branch" + +# Fix permissions on writable directories. +for dir in lock cache feed-icons ; do + chmod 755 "${ttrss_repo_dir}/${dir}" + chown -R "${nginx_user}:${nginx_user}" "${ttrss_repo_dir}/${dir}" +done + +# Generate config.php. +install_template -m 0644 "${ttrss_repo_dir}/config.php" + +# Create postgres user and database. +postgres_create_role "$ttrss_dbhost" "$ttrss_username" +postgres_create_database "$ttrss_dbhost" "$ttrss_dbname" "$ttrss_username" + +# Initialize the database schema. +su -m "$nginx_user" -c "${ttrss_repo_dir}/update.php --update-schema=force-yes" + +# Copy tt-rss LDAP auth plugin. +install_directory -m 0755 "${ttrss_repo_dir}/plugins.local/auth_idm" +install_file -m 0644 "${ttrss_repo_dir}/plugins.local/auth_idm/init.php" + +# Copy tt-rss rc script. +install_file -m 0555 /usr/local/etc/rc.d/ttrssd + +# Allow ttrss user to perform git queries. +git config --system --replace-all safe.directory "$ttrss_repo_dir" + +# Copy TLS certificate for nginx. +install_certificate nginx "$ttrss_https_cert" +install_certificate_key nginx "$ttrss_https_key" + +# 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 + +# 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/ttrss.conf +> /usr/local/etc/php-fpm.d/www.conf + +# Enable and start daemons. +sysrc -v \ + nginx_enable=YES \ + php_fpm_enable=YES \ + ttrssd_enable=YES +service nginx restart +service php_fpm restart +service ttrssd restart + +# Create roles. +for role in "$ttrss_access_role" "$ttrss_admin_role"; do + ldap_add "cn=${role},${roles_basedn}" <<EOF +objectClass: groupOfMembers +cn: ${role} +EOF +done diff --git a/scripts/hostclass/turn_server b/scripts/hostclass/turn_server new file mode 100644 index 0000000..2c01e30 --- /dev/null +++ b/scripts/hostclass/turn_server @@ -0,0 +1,29 @@ +#!/bin/sh + +: ${coturn_secret:="$turn_secret"} +: ${coturn_external_ip:="$BOXCONF_DEFAULT_IPV4"} +: ${coturn_realm:="$turn_domain"} +: ${coturn_threads:="$nproc"} + +coturn_user=coturn +coturn_uid=792 + +add_user \ + -u "$coturn_uid" \ + -c 'Turnserver Psuedo-User' \ + -d /nonexistent \ + -s /usr/sbin/nologin \ + "$coturn_user" + +# Install required packages. +pkg install -y turnserver + +# Copy coturn config file. +install_template -o root -g "$coturn_user" -m 0640 /usr/local/etc/turnserver.conf + +# Start turnserver. +sysrc -v \ + turnserver_enable=YES \ + turnserver_user="$coturn_user" \ + turnserver_group="$coturn_user" +service turnserver restart diff --git a/scripts/hostclass/xmpp_server b/scripts/hostclass/xmpp_server new file mode 100644 index 0000000..1889447 --- /dev/null +++ b/scripts/hostclass/xmpp_server @@ -0,0 +1,132 @@ +#!/bin/sh + +# The LDAP library used by prosody (lualdap) does not support SASL binds. +# Therefore, you must specify the prosody_ldap_password variable. + +# prosody_acme_host= +: ${prosody_admins:=''} +: ${prosody_public_fqdn:="$fqdn"} +: ${prosody_domains:="$email_domain"} +: ${prosody_ldap_passwd:='changeme'} +: ${prosody_dbname:='prosody'} +: ${prosody_dbhost:="$postgres_host"} +: ${prosody_access_role:='xmpp-access'} +: ${prosody_archive_expiration:='1w'} +: ${prosody_upload_sizelimit:='104857600'} # 100 MB +: ${prosody_upload_expiration:='604800'} # 1 week +: ${prosody_upload_quota:='25769803776'} # 24 GB +: ${prosody_turn_port:='3478'} +: ${prosody_turn_host:="$turn_domain"} +: ${prosody_turn_realm:="$turn_domain"} +: ${prosody_turn_secret="$turn_secret"} + +prosody_dn="uid=${prosody_username},${robots_basedn}" +prosody_local_user=prosody +prosody_conf_dir=/usr/local/etc/prosody +prosody_certs_dir="${prosody_conf_dir}/certs" +prosody_keytab="${keytab_dir}/prosody.keytab" +prosody_roster_path="${prosody_conf_dir}/roster.ini" +prosody_http_port=8080 +prosody_upload_dir=/var/db/prosody/http_upload + +prosody_https_cacert="${acme_cert_dir}/nginx.ca.crt" +prosody_https_cert="${acme_cert_dir}/nginx.crt" +prosody_https_key="${acme_cert_dir}/nginx.key" + +# Install required packages. +pkg install -y \ + prosody \ + prosody-modules \ + lua54-luadbi \ + lua54-lualdap \ + nginx + +# Create ZFS dataset for HTTP upload files. +create_dataset -o "mountpoint=${prosody_upload_dir}" "${state_dataset}/http_upload" + +# Set ownership on http_upload directory. +install_directory -o "$prosody_local_user" -g "$prosody_local_user" -m 0750 "$prosody_upload_dir" + +# Create prosody user private group. +ldap_add "cn=${prosody_username},${private_groups_basedn}" <<EOF +objectClass: groupOfMembers +objectClass: posixGroup +cn: ${prosody_username} +gidNumber: ${prosody_uid} +member: uid=${prosody_username},${robots_basedn} +EOF + +# Create prosody user account. +ldap_add "$prosody_dn" <<EOF +objectClass: account +objectClass: posixAccount +uid: ${prosody_username} +cn: ${prosody_username} +uidNumber: ${prosody_uid} +gidNumber: ${prosody_uid} +gecos: Prosody Pseudo-User +loginShell: /sbin/nologin +homeDirectory: /nonexistent +EOF + +# Create principal and keytab. +add_principal -nokey -x "dn=${prosody_dn}" "$prosody_username" + +ktadd -k "$prosody_keytab" "$prosody_username" +chgrp "$prosody_local_user" "$prosody_keytab" +chmod 640 "$prosody_keytab" + +prosody_local_uid=$(id -u "$prosody_local_user") +install_directory -o "$prosody_local_user" -m 0700 "/var/krb5/user/${prosody_local_uid}" +ln -snfv "$prosody_keytab" "/var/krb5/user/${prosody_local_uid}/client.keytab" + +# Set LDAP password for prosody user. +ldap_passwd "$prosody_dn" "$prosody_ldap_password" + +# Create postgres user and database. +postgres_create_role "$prosody_dbhost" "$prosody_username" +postgres_create_database "$prosody_dbhost" "$prosody_dbname" "$prosody_username" + +# Retrieve prosody certificates via ACME proxy. +install_directory -o root -g "$prosody_local_user" -m 0770 "$prosody_certs_dir" +install_file -m 0555 /usr/local/libexec/prosody-acme-proxy +su -m "$prosody_local_user" -c "/usr/local/libexec/prosody-acme-proxy ${prosody_username}@${prosody_acme_host} ${prosody_domains}" + +# Copy prosody configuration. +install_template -o root -g "$prosody_local_user" -m 0640 /usr/local/etc/prosody/prosody.cfg.lua + +# Configure automatic roster. +install_file -m 0555 /usr/local/libexec/prosody-update-roster +install -Cv -m 0640 -o "$prosody_local_user" -g "$prosody_local_user" /dev/null "${prosody_conf_dir}/roster.ini" +su -m "$prosody_local_user" -c "/usr/local/libexec/prosody-update-roster ${prosody_access_role} > ${prosody_roster_path}" + +# Copy prosody crontab. +install_template -m 0644 /etc/cron.d/prosody + +# Configure nginx. +install_template -m 0644 /usr/local/etc/nginx/nginx.conf +sysrc -v nginx_enable=YES +service nginx restart + +install_template -m 0600 /usr/local/etc/sudoers.d/acme +acme_install_certificate \ + -C "$prosody_https_cacert" \ + -c "$prosody_https_cert" \ + -k "$prosody_https_key" \ + -g "$nginx_user" \ + -r 'sudo service nginx reload' \ + "$prosody_public_fqdn" + +# Now that we have the ACME certs, add the nginx vhost. +install_template -m 0644 /usr/local/etc/nginx/vhosts.conf + +# Enable and start daemons. +sysrc -v prosody_enable=YES +service prosody restart +service nginx restart + +# Create access role. +ldap_add "cn=${prosody_access_role},${roles_basedn}" <<EOF +objectClass: groupOfMembers +cn: ${prosody_access_role} +EOF diff --git a/scripts/hostclass/znc_server b/scripts/hostclass/znc_server new file mode 100644 index 0000000..c9f3780 --- /dev/null +++ b/scripts/hostclass/znc_server @@ -0,0 +1,68 @@ +#!/bin/sh + +: ${znc_max_networks:='16'} +: ${znc_access_role:='znc-access'} + +znc_http_port=8443 +znc_home=/usr/local/etc/znc +znc_user=znc +znc_tls_cert="${znc_home}/znc.crt" +znc_tls_key="${znc_home}/znc.key" +znc_clone_user='clone___' + +# Install required packages. +pkg install -y \ + cyrus-sasl-saslauthd \ + nginx \ + znc + +# Create ZFS dataset for ZNC configs. +create_dataset -o "mountpoint=${znc_home}" "${state_dataset}/znc" + +# Set ownership on ZNC dir. +install_directory -o "$znc_user" -g "$znc_user" -m 0755 "$znc_home" + +# Copy TLS certificate for ZNC. +install_certificate -o "$znc_user" -g "$znc_user" znc "$znc_tls_cert" +install_certificate_key -o "$znc_user" -g "$znc_user" znc "$znc_tls_key" + +# Generate ZNC configs. +install_directory -o "$znc_user" -g "$znc_user" -m 0700 \ + "${znc_home}/configs" \ + "${znc_home}/moddata" \ + "${znc_home}/moddata/cyrusauth" + +[ -f "${znc_home}/configs/znc.conf" ] \ + || install_template -o "$znc_user" -g "$znc_user" -m 0600 "${znc_home}/configs/znc.conf" + +install_template -o "$znc_user" -g "$znc_user" -m 0600 "${znc_home}/moddata/cyrusauth/.registry" + +# Copy saslauthd configuration. +# TODO: use ldap module for saslauthd. +install_template -m 0644 \ + /usr/local/lib/sasl2/znc.conf \ + /etc/pam.d/znc + +# Allow znc to read the saslauthd socket. +install_directory -m 0750 -o "$saslauthd_user" -g "$znc_user" "$saslauthd_runtime_dir" + +# Generate nginx configuration. +install_template -m 0644 \ + /usr/local/etc/nginx/nginx.conf \ + /usr/local/etc/nginx/vhosts.conf + +sysrc -v \ + saslauthd_enable=YES \ + saslauthd_flags='-a pam' \ + znc_enable=YES \ + nginx_enable=YES + +service saslauthd restart +service znc status || service znc start +service nginx restart + +# Create access role. +ldap_add "cn=${znc_access_role},${roles_basedn}" <<EOF +objectClass: groupOfMembers +cn: ${znc_access_role} +EOF diff --git a/scripts/hostname/znc1 b/scripts/hostname/znc1 new file mode 100644 index 0000000..dc11b11 --- /dev/null +++ b/scripts/hostname/znc1 @@ -0,0 +1,3 @@ +#!/bin/sh + +cnames=znc diff --git a/scripts/os/freebsd/60-acme b/scripts/os/freebsd/60-acme index 902e674..94b832d 100644 --- a/scripts/os/freebsd/60-acme +++ b/scripts/os/freebsd/60-acme @@ -10,6 +10,9 @@ acme_standalone_port=9080 acme_user=acme acme_home=/var/db/acme acme_webroot=/usr/local/www/acme +acmeproxy_home=/var/spool/acmeproxy + +dhparams_path=/etc/ssl/dhparams.pem pkg install -y acme.sh @@ -22,14 +25,20 @@ else su -m "$acme_user" -c "acme.sh --home ${acme_home} --register-account --email ${acme_email}" fi +if [ "${nginx_public:-}" = true ] && ! [ -f "$dhparams_path" ]; then + openssl dhparam -out "$dhparams_path" 2048 +fi + acme_install_certificate(){ _aic_group=0 _aic_cert_path= _aic_key_path= + _aic_ca_path= _aic_reload_cmd= - while getopts c:g:k:r: _aic_opt; do + while getopts C:c:g:k:r: _aic_opt; do case $_aic_opt in + C) _aic_ca_path=$OPTARG ;; c) _aic_cert_path=$OPTARG ;; g) _aic_group=$OPTARG ;; k) _aic_key_path=$OPTARG ;; @@ -68,8 +77,28 @@ acme_install_certificate(){ fi if [ -n "$_aic_reload_cmd" ]; then - su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path} --reloadcmd '${_aic_reload_cmd}'" + su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path} --ca-file ${aic_ca_path} --reloadcmd '${_aic_reload_cmd}'" else - su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path}" + su -m "$acme_user" -c "acme.sh --home ${acme_home} --install-cert --domain ${_aic_name} --key-file ${_aic_key_path} --fullchain-file ${_aic_cert_path} --ca-file ${aic_ca_path} " fi } + +acme_setup_proxy(){ + [ -n "${acmeproxy_domains:-}" ] || return 0 + + install_directory -o root -g wheel -m 0755 "$acmeproxy_home" + install_directory -o "$acme_user" -g "${acmeproxy_client_gid:-${acmeproxy_client_group}}" -m 0750 "${acmeproxy_home}/certs" + + # Configure SSHD for acmeproxy. + install_template -m 0644 /usr/local/etc/ssh/sshd_config.d/acmeproxy.conf + service sshd reload + + # Acquire ACME certificates for client SFTP. + for domain in $acmeproxy_domains; do + acme_install_certificate \ + -c "${acmeproxy_home}/certs/${domain}.crt" \ + -k "${acmeproxy_home}/certs/${domain}.key" \ + -g "${acmeproxy_client_gid:-${acmeproxy_client_group}}" \ + $domain + done +} diff --git a/scripts/hostname/rlaptop1 b/site/scripts/hostname/rlaptop1 index f346965..f346965 100644 --- a/scripts/hostname/rlaptop1 +++ b/site/scripts/hostname/rlaptop1 diff --git a/vars/common b/vars/common index 18d0e52..92a0c96 100644 --- a/vars/common +++ b/vars/common @@ -3,6 +3,7 @@ site=myhomelab domain=idm.example.com email_domain=example.com +turn_domain=turn.example.com locale=en_US.UTF-8 ntp_pools='pool.ntp.org' root_password=changeme @@ -21,6 +22,8 @@ idm2 2 5.6.7.8" reverse_dns_zones="0.168.192.in-addr.arpa 12.11.10.in-addr.arpa" +kerberized_cidrs=192.168.0.0/24 + rspamd_privkey='changeme with: rspamadm keypair' rspamd_pubkey='changeme with: rspamadm keypair' rspamd_ro_password='changeme' @@ -46,6 +49,8 @@ krb5_renew_lifetime=7d nslcd_min_uid=1000 nscd_ttl=600 nscd_negative_ttl=20 +prosody_username='s-prosody' +prosody_uid=20005 rspamd_port=11334 ssh_authzkeys_uid=789 ssh_authzkeys_username=sshkeys @@ -53,7 +58,7 @@ tcp_buffer_size=2097152 # suitable for 1 GigE nginx_nofile=2048 nginx_worker_connections=768 -if $(( nproc > 4 )); then +if (( nproc > 4 )); then nginx_worker_processes=4 else nginx_worker_processes=$nproc diff --git a/vars/hostclass/asterisk_server b/vars/hostclass/asterisk_server new file mode 100644 index 0000000..daf5fa6 --- /dev/null +++ b/vars/hostclass/asterisk_server @@ -0,0 +1,10 @@ +#!/bin/sh + +asterisk_rtp_port_start=10000 +asterisk_rtp_port_end=10999 + +allowed_tcp_ports='ssh sip sip-tls' +allowed_udp_ports="ssh sip sip-tls ${asterisk_rtp_port_start}:${asterisk_rtp_port_end}" + +acme=true +acme_standalone=true diff --git a/vars/hostclass/authoritative_nameserver b/vars/hostclass/authoritative_nameserver new file mode 100644 index 0000000..a421b7c --- /dev/null +++ b/vars/hostclass/authoritative_nameserver @@ -0,0 +1,4 @@ +#!/bin/sh + +allowed_tcp_ports='ssh domain' +allowed_udp_ports='domain' diff --git a/vars/hostclass/bitwarden_server b/vars/hostclass/bitwarden_server new file mode 100644 index 0000000..5ae7588 --- /dev/null +++ b/vars/hostclass/bitwarden_server @@ -0,0 +1,3 @@ +#!/bin/sh + +allowed_tcp_ports="ssh http https" diff --git a/vars/hostclass/dav_server b/vars/hostclass/dav_server new file mode 100644 index 0000000..2a4b250 --- /dev/null +++ b/vars/hostclass/dav_server @@ -0,0 +1,4 @@ +#!/bin/sh + +allowed_tcp_ports='ssh http https' +nginx_gssapi=true diff --git a/vars/hostclass/pkg_repository b/vars/hostclass/pkg_repository index dbd49a7..4752685 100644 --- a/vars/hostclass/pkg_repository +++ b/vars/hostclass/pkg_repository @@ -1,3 +1,4 @@ #!/bin/sh allowed_tcp_ports='ssh http' +nginx_redirect=false diff --git a/vars/hostclass/postgresql_server b/vars/hostclass/postgresql_server new file mode 100644 index 0000000..500e59b --- /dev/null +++ b/vars/hostclass/postgresql_server @@ -0,0 +1,3 @@ +#!/bin/sh + +allowed_tcp_ports='ssh postgresql' diff --git a/vars/hostclass/public_webserver b/vars/hostclass/public_webserver new file mode 100644 index 0000000..b6a9c9d --- /dev/null +++ b/vars/hostclass/public_webserver @@ -0,0 +1,5 @@ +#!/bin/sh + +allowed_tcp_ports='ssh http https' +acme=true +nginx_public=true diff --git a/vars/hostclass/ttrss_server b/vars/hostclass/ttrss_server new file mode 100644 index 0000000..2a4b250 --- /dev/null +++ b/vars/hostclass/ttrss_server @@ -0,0 +1,4 @@ +#!/bin/sh + +allowed_tcp_ports='ssh http https' +nginx_gssapi=true diff --git a/vars/hostclass/turn_server b/vars/hostclass/turn_server new file mode 100644 index 0000000..06cc6ae --- /dev/null +++ b/vars/hostclass/turn_server @@ -0,0 +1,8 @@ +#!/bin/sh + +coturn_listen_port=3478 +coturn_min_port=49152 +coturn_max_port=65535 + +allowed_tcp_ports="ssh ${coturn_listen_port}" +allowed_udp_ports="${coturn_listen_port} ${coturn_min_port}:${coturn_max_port}" diff --git a/vars/hostclass/xmpp_server b/vars/hostclass/xmpp_server new file mode 100644 index 0000000..204d1ba --- /dev/null +++ b/vars/hostclass/xmpp_server @@ -0,0 +1,5 @@ +#!/bin/sh + +acme=true +allowed_tcp_ports='ssh http https xmpp-client xmpp-server' +nginx_public=true diff --git a/vars/hostclass/znc_server b/vars/hostclass/znc_server new file mode 100644 index 0000000..7e6ad77 --- /dev/null +++ b/vars/hostclass/znc_server @@ -0,0 +1,4 @@ +#!/bin/sh + +znc_irc_port=6697 +allowed_tcp_ports="ssh http https ${znc_irc_port}" diff --git a/vars/hostname/bitwarden1 b/vars/hostname/bitwarden1 new file mode 100644 index 0000000..659336e --- /dev/null +++ b/vars/hostname/bitwarden1 @@ -0,0 +1,4 @@ +#!/bin/sh + +cnames=bitwarden +vaultwarden_fqdn="bitwarden.${domain}" diff --git a/vars/hostname/dav1 b/vars/hostname/dav1 new file mode 100644 index 0000000..cab4c08 --- /dev/null +++ b/vars/hostname/dav1 @@ -0,0 +1,3 @@ +#!/bin/sh + +cnames=dav diff --git a/vars/hostname/ns1 b/vars/hostname/ns1 new file mode 100644 index 0000000..cb59104 --- /dev/null +++ b/vars/hostname/ns1 @@ -0,0 +1,3 @@ +#!/bin/sh + +cnames=ns diff --git a/vars/hostname/pbx1 b/vars/hostname/pbx1 new file mode 100644 index 0000000..4931dd6 --- /dev/null +++ b/vars/hostname/pbx1 @@ -0,0 +1,3 @@ +#!/bin/sh + +cnames=pbx diff --git a/vars/hostname/postgres1 b/vars/hostname/postgres1 new file mode 100644 index 0000000..a38ba94 --- /dev/null +++ b/vars/hostname/postgres1 @@ -0,0 +1,4 @@ +#!/bin/sh + +memsize=$(( 8 * 1024 * 1024 * 1024)) +cnames=postgres diff --git a/vars/hostname/ttrss1 b/vars/hostname/ttrss1 new file mode 100644 index 0000000..d6fbb39 --- /dev/null +++ b/vars/hostname/ttrss1 @@ -0,0 +1,4 @@ +#!/bin/sh + +cnames=ttrss +ttrss_hostname="ttrss.${domain}" diff --git a/vars/hostname/turn1 b/vars/hostname/turn1 new file mode 100644 index 0000000..86e970a --- /dev/null +++ b/vars/hostname/turn1 @@ -0,0 +1,3 @@ +#!/bin/sh + +cnames=turn diff --git a/vars/hostname/www1 b/vars/hostname/www1 new file mode 100644 index 0000000..88a683e --- /dev/null +++ b/vars/hostname/www1 @@ -0,0 +1,5 @@ +#!/bin/sh + +cnames='www' +acmeproxy_client_group=$prosody_username +acmeproxy_client_gid=$prosody_uid diff --git a/vars/hostname/xmpp1 b/vars/hostname/xmpp1 new file mode 100644 index 0000000..e094b54 --- /dev/null +++ b/vars/hostname/xmpp1 @@ -0,0 +1,5 @@ +#!/bin/sh + +cnames=xmpp +prosody_acme_host=www1 +prosody_public_fqdn=xmpp.example.com diff --git a/vars/os/freebsd b/vars/os/freebsd index 5fae2d6..d13c84e 100644 --- a/vars/os/freebsd +++ b/vars/os/freebsd @@ -14,6 +14,7 @@ export ASSUME_ALWAYS_YES=yes keytab_dir=/var/db/keytabs nfscbd_port=7745 nginx_user=www +nginx_conf_dir=/usr/local/etc/nginx nslcd_user=nslcd php_version=82 postgresql_version=16 |