provisioning tool for building opinionated architecture
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
8.8 KiB

9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
  1. #!/bin/bash
  2. ### FUNCTIONS
  3. ### ---------
  4. function prepare_config_hardened() {
  5. mkdir -p "$HARDEN_CONFIGDIR"
  6. }
  7. function pubkey_authorize() {
  8. local PREFIX="harden:pubkey:authorize"
  9. if [[ ! -d $HOME/.ssh ]]; then
  10. echo -n "create .ssh folder for the first time ..."
  11. mkdir -m 700 ~/.ssh
  12. PREFIX="" echo "OK"
  13. else
  14. local security_issue_in_ssh_folder
  15. security_issue_in_ssh_folder=$(find "$HOME/.ssh" -perm -go=r | wc -l)
  16. if [[ $security_issue_in_ssh_folder -gt 0 ]]; then
  17. echo -n "force security in .ssh folder for <$CURRENT_USER> ..."
  18. chmod -R u+rwX,go-rwx "/home/$CURRENT_USER/.ssh"
  19. PREFIX="" echo "OK"
  20. else
  21. echo "security in .ssh folder for <$CURRENT_USER> approved!"
  22. fi
  23. fi
  24. pubkey_value=$(yq ".authorized.pubkey" "$HARDEN_CONFIGFILE")
  25. if [[ ! -f /home/$CURRENT_USER/.ssh/authorized_keys ]]; then
  26. echo -n "authorized_keys first time ..."
  27. PREFIX="" echo "$pubkey_value" >"$HOME/.ssh/authorized_keys"
  28. chmod u+rw,go-rwx "/home/$CURRENT_USER/.ssh/authorized_keys"
  29. PREFIX="" echo "OK"
  30. else
  31. if ! grep -q "^$pubkey_value" "/home/$CURRENT_USER/.ssh/authorized_keys"; then
  32. echo -n "pubkey <$CURRENT_USER> appended to <.ssh/authorized_keys> ..."
  33. echo "$pubkey_value" >>"$HOME/.ssh/authorized_keys"
  34. PREFIX="" echo "OK"
  35. else
  36. echo "pubkey <$CURRENT_USER> already authorized!"
  37. fi
  38. fi
  39. }
  40. function sudoers() {
  41. local PREFIX="harden:sudoers"
  42. if [[ -d /etc/sudoers.d ]]; then
  43. echo -n "add $CURRENT_USER and no more ..."
  44. sudo env current_user="$CURRENT_USER" tera -e --env-key env --env-only -o /etc/sudoers -t "$MIAOU_BASEDIR/templates/hardened/sudoers.j2" >/dev/null
  45. rm /etc/sudoers.d -rf
  46. grep -Eq "^debian" /etc/passwd && userdel -rf debian
  47. grep -Eq "^sudo" /etc/group && groupdel sudo
  48. passwd -dq root
  49. passwd -dq "$CURRENT_USER"
  50. PREFIX="" echo "OK"
  51. else
  52. echo "sudo authorized for <$CURRENT_USER> only!"
  53. fi
  54. }
  55. function sshd() {
  56. local PREFIX="harden:sshd"
  57. if [[ ! -f /etc/ssh/sshd_config ]]; then
  58. sudo apt install -y openssh-server
  59. else
  60. echo "sshd already installed!"
  61. fi
  62. if ! grep -Eq "^Port 2222" /etc/ssh/sshd_config; then
  63. echo -n "replacing sshd ..."
  64. sudo env current_user="$CURRENT_USER" tera -e --env-key env --env-only -o /etc/ssh/sshd_config -t "$MIAOU_BASEDIR/templates/hardened/sshd_config.j2" >/dev/null
  65. sudo systemctl restart sshd
  66. PREFIX="" echo "OK"
  67. else
  68. echo "already done!"
  69. fi
  70. }
  71. function prepare_proxy() {
  72. local PREFIX="harden:proxy"
  73. if ! grep -Eq "^precedence ::ffff:0:0/96.*" /etc/gai.conf; then
  74. echo "prefer ipv4 ..."
  75. sudo /opt/miaou-bash/tools/append_or_replace "^precedence ::ffff:0:0/96.*" "precedence ::ffff:0:0/96 100" /etc/gai.conf
  76. echo "OK"
  77. else
  78. echo "ipv4 already prefered!"
  79. fi
  80. if ! grep -Eq "^net.ipv4.ip_forward=1" /etc/sysctl.conf; then
  81. echo "allow forwarding from kernel ..."
  82. sudo /opt/miaou-bash/tools/append_or_replace "^net.ipv4.ip_forward=1.*" "net.ipv4.ip_forward=1" /etc/sysctl.conf
  83. sudo sysctl -p
  84. echo "OK"
  85. else
  86. echo "kernel forwarding already allowed!"
  87. fi
  88. }
  89. function set_current_user {
  90. local PREFIX="harden:environment"
  91. CURRENT_USER=$(id -un)
  92. echo "current user is <$CURRENT_USER>"
  93. }
  94. function load_configuration {
  95. local PREFIX="harden:configuration:load"
  96. if [[ ! -f "$HARDEN_CONFIGFILE" ]]; then
  97. echo "configuration requires further details ..."
  98. cp "$MIAOU_BASEDIR/templates/hardened/hardened.yaml.sample" "$HARDEN_CONFIGFILE"
  99. echo "OK"
  100. fi
  101. editor "$HARDEN_CONFIGFILE"
  102. }
  103. function check_configuration {
  104. local PREFIX="harden:configuration:check"
  105. check_yaml_defined_value "$HARDEN_CONFIGFILE" 'authorized.pubkey'
  106. check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.to'
  107. check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.from'
  108. check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.smtp.server'
  109. }
  110. function set_timezone_if_defined {
  111. local PREFIX="harden:timezone"
  112. timezone=$(yq ".timezone" "$HARDEN_CONFIGFILE")
  113. if [[ "$timezone" != null ]]; then
  114. if ! grep -q "$timezone" /etc/timezone; then
  115. if [[ -f "/usr/share/zoneinfo/$timezone" ]]; then
  116. echo "set timezone to $timezone ..."
  117. sudo ln -fs "/usr/share/zoneinfo/$timezone" /etc/localtime
  118. sudo dpkg-reconfigure -f noninteractive tzdata
  119. echo OK
  120. else
  121. echoerr "unkown timezone: <$timezone>, please edit <$HARDEN_CONFIGFILE> and change to a correct value" && exit 98
  122. fi
  123. else
  124. echo "timezone <$timezone> already set!"
  125. fi
  126. fi
  127. }
  128. function mailer_alert() {
  129. local PREFIX="harden:mailer"
  130. if [[ ! -f /etc/msmtprc ]]; then
  131. for i in exim4-config libevent-2.1-7 libgnutls-dane0 libunbound8; do
  132. if dpkg -l "$i" 2>/dev/null | grep -q ^ii && echo 'installed'; then
  133. echo "purging package <$i> ..."
  134. apt purge -y "$i"
  135. echo "OK"
  136. fi
  137. done
  138. echo "installing <msmtp> ..."
  139. sudo /opt/miaou-bash/tools/idem_apt_install msmtp msmtp-mta mailutils bsd-mailx
  140. echo "OK"
  141. echo "configuring </etc/aliases>"
  142. sudo env current_user="$CURRENT_USER" tera -e --env-key env -o /etc/aliases -t "$MIAOU_BASEDIR/templates/hardened/mailer/aliases.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
  143. echo "OK"
  144. # populate environment variable with fqdn
  145. fqdn=$(hostname -f)
  146. echo "configuring </etc/mail.rc>"
  147. sudo env current_user="$CURRENT_USER" fqdn="$fqdn" tera -e --env-key env -o /etc/mail.rc -t "$MIAOU_BASEDIR/templates/hardened/mailer/mail.rc.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
  148. echo "OK"
  149. echo "generating </etc/msmtprc> configuration file ..."
  150. sudo env fqdn="$fqdn" tera -e --env-key env -o /etc/msmtprc -t "$MIAOU_BASEDIR/templates/hardened/mailer/msmtprc.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
  151. sudo chown root:msmtp /etc/msmtprc
  152. sudo chmod 640 /etc/msmtprc
  153. echo "OK"
  154. else
  155. echo "mailer <msmtp> already configured!"
  156. fi
  157. }
  158. function alert_at_boot() {
  159. local PREFIX="harden:alert:boot"
  160. if ! systemctl is-enabled --quiet on_startup.service 2>/dev/null; then
  161. echo "installing <on_startup.service> on systemd..."
  162. sudo cp "$MIAOU_BASEDIR/templates/hardened/systemd/on_startup.service" /etc/systemd/system/on_startup.service
  163. sudo systemctl daemon-reload
  164. sudo systemctl enable on_startup.service
  165. REBOOT=true
  166. echo "OK"
  167. else
  168. echo "systemd <on_startup.service> already enabled!"
  169. fi
  170. }
  171. function show_reboot_on_purpose() {
  172. if "$REBOOT"; then
  173. PREFIX="harden:reboot" echowarn "we recommend reboot on purpose, Reboot NOW?"
  174. else
  175. PREFIX="harden" echo "success"
  176. fi
  177. }
  178. function disable_systemd_resolved() {
  179. PREFIX="harden:systemd:resolved"
  180. if file /etc/resolv.conf | grep -q /run/systemd/resolve/stub-resolv.conf; then
  181. echo "disabling systemd-resolved..."
  182. sudo systemctl stop systemd-resolved.service
  183. sudo systemctl disable systemd-resolved.service
  184. sudo rm /etc/resolv.conf
  185. sudo tee /etc/resolv.conf &>/dev/null <<EOF
  186. nameserver 1.1.1.1
  187. EOF
  188. echo "OK"
  189. else
  190. echo "systemd-resolved already disabled!"
  191. fi
  192. }
  193. function alert_at_ssh_password() {
  194. local PREFIX="harden:alert:ssh:password"
  195. if ! grep -Eq "^session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" /etc/pam.d/sshd; then
  196. echo "installing alert_at_ssh_password..."
  197. sudo cp "$MIAOU_BASEDIR/templates/hardened/pam/alert_ssh_password.sh" /usr/local/bin/
  198. sudo chmod 700 /usr/local/bin/alert_ssh_password.sh
  199. sudo /opt/miaou-bash/tools/append_or_replace "^session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" "session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" /etc/pam.d/sshd
  200. echo "OK"
  201. else
  202. echo "alert_at_ssh_password already enabled!"
  203. fi
  204. }
  205. function customize_motd {
  206. local PREFIX="harden:motd:customize"
  207. if [[ ! -f /etc/update-motd.d/80-users ]]; then
  208. echo "customizing motd..."
  209. sudo /opt/miaou-bash/tools/idem_apt_install figlet lsb-release
  210. sudo rm -f /etc/motd
  211. sudo mkdir -p /etc/update-motd.d
  212. sudo rm -f /etc/update-motd.d/*
  213. sudo cp "$MIAOU_BASEDIR"/templates/hardened/motd/* /etc/update-motd.d/
  214. sudo chmod +x /etc/update-motd.d/*
  215. echo "OK"
  216. else
  217. echo "motd already customized!"
  218. fi
  219. }
  220. ### CONSTANTS
  221. ### ---------
  222. MIAOU_BASEDIR=$(readlink -f "$(dirname "$0")/..")
  223. readonly HARDEN_CONFIGDIR="$HOME/.config/hardened"
  224. readonly HARDEN_CONFIGFILE="$HARDEN_CONFIGDIR/hardened.yaml"
  225. ### MAIN
  226. ### ----
  227. # shellcheck source=/dev/null
  228. . "$MIAOU_BASEDIR/lib/functions.sh"
  229. miaou_init
  230. REBOOT=false
  231. PREFIX="harden"
  232. : $PREFIX
  233. sudo_required
  234. install_miaou_bash
  235. install_mandatory_commands
  236. prepare_config_hardened
  237. set_current_user
  238. check_configuration 2>/dev/null || load_configuration
  239. check_configuration
  240. pubkey_authorize
  241. sshd
  242. prepare_proxy
  243. prepare_nftables
  244. disable_systemd_resolved
  245. set_timezone_if_defined
  246. mailer_alert
  247. alert_at_boot
  248. alert_at_ssh_password
  249. customize_motd
  250. show_reboot_on_purpose