From aee57a8b896df352612c457519d44fe03ad52ee2 Mon Sep 17 00:00:00 2001 From: Alexandre Pires Date: Sat, 20 Sep 2025 21:34:33 +0200 Subject: [PATCH] Refactor Gitea and SSH configurations, update backup scripts, and enhance Nginx settings - Updated SSH configuration for Gitea to disable banner and TTY, and modified the AuthorizedKeysCommand. - Simplified gitea-shell script to directly call the k8s_gitea_shell command with required parameters. - Removed unused gitea-auth script from playbook_gitea.yml. - Updated systools_version in playbook_systools.yml to 0.4.5. - Enhanced ssh_locker_helper to copy redirect URL to clipboard based on OS. - Added a new script test_imaps for IMAP testing. - Updated Terraform configurations for various applications, including: - Added a backup script for MariaDB with retention policy. - Changed Gitea version to 1.24-rootless and adjusted SSH settings. - Updated Nginx configurations to log errors and access to stderr/stdout. - Refactored services to use ClusterIP type and adjusted security contexts for deployments. - Added temporary storage for applications using empty_dir. - Enhanced backup.sh scripts for better error handling and logging. --- .../files/configs/sshd_config.d/gitea.conf | 4 +- ansible/files/scripts/gitea-shell | 4 +- ansible/playbook_gitea.yml | 1 - ansible/playbook_systools.yml | 2 +- bin/ssh_locker_helper | 17 +++++- bin/test_imaps | 5 ++ terraform/apps/dev-01/apps.tf | 7 +-- terraform/apps/prod-01/apps.tf | 3 +- terraform/apps/prod-01/config.tf | 36 ++++++++++++- .../apps/prod-01/resources/alexpires.me.conf | 10 ---- terraform/modules/apps/gitea/main.tf | 19 +++++-- .../modules/apps/gitea/resources/app.ini.tpl | 4 ++ .../modules/apps/gitea/resources/robots.txt | 2 + terraform/modules/apps/gitea/variables.tf | 4 +- terraform/modules/apps/m3uproxy/main.tf | 4 +- terraform/modules/apps/m3uproxy/vpn.tf | 3 +- terraform/modules/apps/mail/config.tf | 4 +- terraform/modules/apps/mail/dovecot.tf | 17 +++--- terraform/modules/apps/mail/postfix.tf | 9 ++-- .../apps/mail/resources/postfix/stunnel.conf | 2 +- terraform/modules/apps/mail/stunnel.tf | 7 +++ terraform/modules/apps/nextcloud/ingress.tf | 1 + terraform/modules/apps/nextcloud/redis.tf | 2 + .../modules/apps/nginx-reverse-proxy/main.tf | 52 +++++++++++++++---- .../resources/nginx/nginx.conf | 9 ++-- .../resources/nginx/streams.d/stream.conf.tpl | 16 +++--- terraform/modules/apps/nginx/main.tf | 21 +++++--- .../modules/apps/nginx/resources/nginx.conf | 9 ++-- terraform/modules/apps/open-webui/webui.tf | 1 + terraform/modules/apps/rustdesk/main.tf | 32 ++++++++---- terraform/modules/apps/sftpgo/main.tf | 6 ++- terraform/modules/apps/template/main.tf | 1 + terraform/modules/db/mariadb/main.tf | 50 +++++++++++++++--- .../modules/db/mariadb/resources/backup.sh | 20 +++++++ .../utils/scw_rclone/resources/backup.sh | 2 +- 35 files changed, 284 insertions(+), 102 deletions(-) create mode 100644 bin/test_imaps create mode 100644 terraform/modules/apps/gitea/resources/robots.txt create mode 100644 terraform/modules/db/mariadb/resources/backup.sh diff --git a/ansible/files/configs/sshd_config.d/gitea.conf b/ansible/files/configs/sshd_config.d/gitea.conf index 729d953..bd87464 100644 --- a/ansible/files/configs/sshd_config.d/gitea.conf +++ b/ansible/files/configs/sshd_config.d/gitea.conf @@ -1,3 +1,5 @@ Match User git + Banner none + PermitTTY no AuthorizedKeysCommandUser git - AuthorizedKeysCommand /usr/local/bin/k8s_gitea_auth -u %u -t %t -k %k \ No newline at end of file + AuthorizedKeysCommand /usr/local/bin/k8s_gitea_auth -r gitea gitea-app -u %u -t %t -k %k \ No newline at end of file diff --git a/ansible/files/scripts/gitea-shell b/ansible/files/scripts/gitea-shell index 73a0eb0..4d924eb 100644 --- a/ansible/files/scripts/gitea-shell +++ b/ansible/files/scripts/gitea-shell @@ -1,4 +1,2 @@ #!/bin/bash -NAMESPACE=gitea -PREFIX=gitea-app -/usr/local/bin/k8s_gitea_shell "$NAMESPACE" "$PREFIX" "$@" +exec /usr/local/bin/k8s_gitea_shell -r gitea gitea-app "$@" \ No newline at end of file diff --git a/ansible/playbook_gitea.yml b/ansible/playbook_gitea.yml index f38a5b5..beafd18 100644 --- a/ansible/playbook_gitea.yml +++ b/ansible/playbook_gitea.yml @@ -15,7 +15,6 @@ mysql_group_id: 107 gitea_sshd_config: "/etc/ssh/sshd_config.d/03-gitea.conf" gitea_scripts: - - "scripts/gitea-auth" - "scripts/gitea-shell" tags: always diff --git a/ansible/playbook_systools.yml b/ansible/playbook_systools.yml index fe54c59..612340c 100644 --- a/ansible/playbook_systools.yml +++ b/ansible/playbook_systools.yml @@ -7,7 +7,7 @@ tasks: - name: Set required facts ansible.builtin.set_fact: - systools_version: "{{ systools_version | default('0.2.0') }}" + systools_version: "{{ systools_version | default('0.4.5') }}" ssh_locker_timeout: "{{ ssh_locker_timeout | default('5m') }}" tags: always diff --git a/bin/ssh_locker_helper b/bin/ssh_locker_helper index dc082e3..71dc27f 100755 --- a/bin/ssh_locker_helper +++ b/bin/ssh_locker_helper @@ -20,8 +20,21 @@ response=$(curl -s -o /dev/null -w "%{redirect_url}" \ -H "X-Auth-Token: $SERVER_API_ACCESS_TOKEN" \ -d '{"user":"'$1'","action":"'$2'"}') + if [ -n "$response" ]; then - xdg-open "$response" + if grep -qi microsoft /proc/version; then + printf "%s" "$response" | xclip -selection clipboard + echo "Redirect URL copied to clipboard." + else + if [[ "$(uname -a)" == *"Darwin"* ]]; then + printf "%s" "$response" | pbcopy + echo "Redirect URL copied to clipboard." + else + xdg-open "$response" + echo "Opening in default web browser..." + fi + fi else echo "No redirect URL received." -fi \ No newline at end of file +fi + diff --git a/bin/test_imaps b/bin/test_imaps new file mode 100644 index 0000000..b855355 --- /dev/null +++ b/bin/test_imaps @@ -0,0 +1,5 @@ +host=imap.alexpires.me +timeout 5 openssl s_client -starttls smtp -connect ${host}:21115 -brief +timeout 5 openssl s_client -starttls smtp -connect ${host}:465 -brief &1 | grep -E "220|250" >/dev/null +echo $? + diff --git a/terraform/apps/dev-01/apps.tf b/terraform/apps/dev-01/apps.tf index 54c92f5..c2a09a4 100644 --- a/terraform/apps/dev-01/apps.tf +++ b/terraform/apps/dev-01/apps.tf @@ -4,6 +4,7 @@ module "open-webui" { persistent_folder = local.persistent_folder fqdn = local.open_webui_fqdn ollama_proxy = local.ollama_proxy + tag = "0.6-slim" } module "samba" { @@ -43,7 +44,7 @@ module "nextcloud" { module "comfyui_proxy" { source = "../../modules/apps/wol_proxy" - upstream = local.comfyui_proxy + upstream = local.comfyui_proxy proxy_port = local.comfyui_proxy.port - namespace = "comfyui" -} \ No newline at end of file + namespace = "comfyui" +} diff --git a/terraform/apps/prod-01/apps.tf b/terraform/apps/prod-01/apps.tf index e8f4cbe..58a3ce2 100644 --- a/terraform/apps/prod-01/apps.tf +++ b/terraform/apps/prod-01/apps.tf @@ -87,8 +87,6 @@ module "gitea" { smtp_passwd = local.mail_app_api_secret_key secret_key = var.gitea_secret_key internal_token = var.gitea_internal_token - disable_ssh = false - ssh_port = 22 disable_registration = true } } @@ -124,4 +122,5 @@ module "reverse_proxy" { services = local.reverse_proxy_services wireguard_config = local.reverse_proxy_wireguard_config auth_token = var.nginx_token_bearer + streams = local.streams } diff --git a/terraform/apps/prod-01/config.tf b/terraform/apps/prod-01/config.tf index be23b4a..d583f59 100644 --- a/terraform/apps/prod-01/config.tf +++ b/terraform/apps/prod-01/config.tf @@ -18,7 +18,7 @@ locals { } # gitea - gitea_version = "1.23.7" + gitea_version = "1.24-rootless" gitea_fqdn = "code.${local.primary_domain}" # sftpgo @@ -77,6 +77,40 @@ locals { ] #reverse proxy settings + + streams = { + "imap" = { + port = 993 + upstream = "imap.mail.svc.cluster.local" + protocol = "tcp" + } + "smtps" = { + port = 465 + upstream = "smtps.mail.svc.cluster.local" + protocol = "tcp" + } + "21115-tcp" = { + port = 21115 + upstream = "tcp.rustdesk.svc.cluster.local" + protocol = "tcp" + } + "21116-tcp" = { + port = 21116 + upstream = "tcp.rustdesk.svc.cluster.local" + protocol = "tcp" + } + "21116-udp" = { + port = 21116 + upstream = "udp.rustdesk.svc.cluster.local" + protocol = "udp" + } + "21117-tcp" = { + port = 21117 + upstream = "tcp.rustdesk.svc.cluster.local" + protocol = "tcp" + } + } + reverse_proxy_wireguard_config = { private_key = var.wireguard_1_private_key public_key = var.wireguard_1_public_key diff --git a/terraform/apps/prod-01/resources/alexpires.me.conf b/terraform/apps/prod-01/resources/alexpires.me.conf index 0da8286..9cce716 100644 --- a/terraform/apps/prod-01/resources/alexpires.me.conf +++ b/terraform/apps/prod-01/resources/alexpires.me.conf @@ -1,15 +1,5 @@ resolver kube-dns.kube-system.svc.cluster.local valid=10s; -location ^~ /config/dav { - proxy_pass https://web.sftpgo.svc.cluster.local/config/dav; - 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_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; -} - location ^~ /api/ssh_locker/ { rewrite ^/api/ssh_locker/(.*)$ /$1 break; proxy_pass https://backend.ssh-locker-web.svc.cluster.local; diff --git a/terraform/modules/apps/gitea/main.tf b/terraform/modules/apps/gitea/main.tf index b3c1db5..525273e 100644 --- a/terraform/modules/apps/gitea/main.tf +++ b/terraform/modules/apps/gitea/main.tf @@ -118,26 +118,29 @@ resource "kubernetes_deployment" "gitea" { security_context { allow_privilege_escalation = false + run_as_group = 1000 + run_as_user = 1000 + read_only_root_filesystem = true } port { container_port = 3000 name = "http" } - port { - container_port = 22 - name = "ssh" - } volume_mount { mount_path = "/data" name = "persistent-storage" } volume_mount { - mount_path = "/data/gitea/conf/app.ini" + mount_path = "/etc/gitea/app.ini" name = "gitea-config" sub_path = "app.ini" } + volume_mount { + name = "tmp" + mount_path = "/tmp" + } dynamic "volume_mount" { for_each = var.tls_enabled ? [1] : [] content { @@ -163,6 +166,12 @@ resource "kubernetes_deployment" "gitea" { } } } + volume { + name = "tmp" + empty_dir { + medium = "Memory" + } + } dynamic "volume" { for_each = var.tls_enabled ? [1] : [] content { diff --git a/terraform/modules/apps/gitea/resources/app.ini.tpl b/terraform/modules/apps/gitea/resources/app.ini.tpl index d13c0ee..5fe7c79 100644 --- a/terraform/modules/apps/gitea/resources/app.ini.tpl +++ b/terraform/modules/apps/gitea/resources/app.ini.tpl @@ -25,12 +25,16 @@ PROTOCOL = http ROOT_URL = http://${DOMAIN} %{ endif ~} DISABLE_SSH = ${DISABLE_SSH} +START_SSH_SERVER = true SSH_PORT = ${SSH_PORT} SSH_LISTEN_PORT = ${SSH_PORT} +SSH_ROOT_PATH = /data/git/.ssh +SSH_AUTHORIZED_KEYS_BACKUP = true LFS_START_SERVER = true LFS_JWT_SECRET = ${LFS_JWT_SECRET} DOMAIN = ${DOMAIN} OFFLINE_MODE = false +SHELL = /bin/sh [lfs] PATH = /data/git/lfs diff --git a/terraform/modules/apps/gitea/resources/robots.txt b/terraform/modules/apps/gitea/resources/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/terraform/modules/apps/gitea/resources/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/terraform/modules/apps/gitea/variables.tf b/terraform/modules/apps/gitea/variables.tf index f4e497d..bc06f9c 100644 --- a/terraform/modules/apps/gitea/variables.tf +++ b/terraform/modules/apps/gitea/variables.tf @@ -32,7 +32,7 @@ variable "db_root_password" { variable "tag" { description = "The version of the websites to install" type = string - default = "1.23.4" + default = "latest-rootless" } variable "fqdn" { @@ -77,7 +77,7 @@ variable "app_config" { run_mode = optional(string, "prod") http_port = optional(string, "3000") disable_ssh = optional(bool, false) - ssh_port = optional(number, 22) + ssh_port = optional(number, 2222) db_host = optional(string, "mariadb") db_port = optional(string, "3306") db_name = optional(string, "gitea") diff --git a/terraform/modules/apps/m3uproxy/main.tf b/terraform/modules/apps/m3uproxy/main.tf index 8eb14fe..f8f6afd 100644 --- a/terraform/modules/apps/m3uproxy/main.tf +++ b/terraform/modules/apps/m3uproxy/main.tf @@ -142,6 +142,7 @@ resource "kubernetes_deployment" "m3uproxy" { allow_privilege_escalation = false run_as_user = 1000 run_as_group = 1000 + read_only_root_filesystem = true } volume_mount { @@ -232,7 +233,8 @@ resource "kubernetes_service" "m3uproxy" { port = 8080 target_port = "http" } - cluster_ip = "None" + type = "ClusterIP" + # cluster_ip = "None" } } diff --git a/terraform/modules/apps/m3uproxy/vpn.tf b/terraform/modules/apps/m3uproxy/vpn.tf index c835314..b6c18f7 100644 --- a/terraform/modules/apps/m3uproxy/vpn.tf +++ b/terraform/modules/apps/m3uproxy/vpn.tf @@ -213,6 +213,7 @@ resource "kubernetes_service" "proxy_pt" { port { port = 3128 } - cluster_ip = "None" + type = "ClusterIP" + # cluster_ip = "None" } } diff --git a/terraform/modules/apps/mail/config.tf b/terraform/modules/apps/mail/config.tf index 5f74564..3697172 100644 --- a/terraform/modules/apps/mail/config.tf +++ b/terraform/modules/apps/mail/config.tf @@ -31,7 +31,7 @@ locals { MY_DESTINATION = join(",", [for account in var.email_accounts : account.domain]) MY_NETWORKS = "127.0.0.0/8" MAILNAME = "smtp.${var.primary_domain}" - DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local" + DOVECOT_LMTP_ADDRESS = "lmtp.mail.svc.cluster.local" DOVECOT_LMTP_PORT = 31024 LOG_TO_STDOUT = 0 } @@ -64,7 +64,7 @@ locals { password = job.password mailbox = job.mailbox delete_after = job.delete_after - dovecot_lmtp_address = "dovecot-lmtp.mail.svc.cluster.local" + dovecot_lmtp_address = "lmtp.mail.svc.cluster.local" dovecot_lmtp_port = 31024 }) } diff --git a/terraform/modules/apps/mail/dovecot.tf b/terraform/modules/apps/mail/dovecot.tf index 049ab16..fd1c275 100644 --- a/terraform/modules/apps/mail/dovecot.tf +++ b/terraform/modules/apps/mail/dovecot.tf @@ -59,7 +59,7 @@ resource "kubernetes_deployment" "dovecot" { } } strategy { - type = "Recreate" + type = "RollingUpdate" } template { metadata { @@ -81,7 +81,6 @@ resource "kubernetes_deployment" "dovecot" { image = "dovecot/dovecot:${var.dovecot_tag}" port { container_port = 31993 - host_port = 993 } port { name = "lmtp" @@ -207,7 +206,7 @@ resource "kubernetes_deployment" "dovecot" { resource "kubernetes_service" "dovecot" { metadata { namespace = kubernetes_namespace.mail.metadata[0].name - name = "dovecot" + name = "imap" } spec { @@ -221,7 +220,7 @@ resource "kubernetes_service" "dovecot" { target_port = 31993 } - type = "LoadBalancer" + type = "ClusterIP" } lifecycle { @@ -233,7 +232,7 @@ resource "kubernetes_service" "dovecot" { resource "kubernetes_service" "dovecot_lmtp" { metadata { - name = "dovecot-lmtp" + name = "lmtp" namespace = kubernetes_namespace.mail.metadata[0].name } @@ -246,13 +245,14 @@ resource "kubernetes_service" "dovecot_lmtp" { port = 31024 target_port = 31024 } - type = "ClusterIP" + type = "ClusterIP" + cluster_ip = "None" } } resource "kubernetes_service" "dovecot_auth" { metadata { - name = "dovecot-auth" + name = "auth" namespace = kubernetes_namespace.mail.metadata[0].name } @@ -265,6 +265,7 @@ resource "kubernetes_service" "dovecot_auth" { port = 31000 target_port = 31000 } - type = "ClusterIP" + type = "ClusterIP" + cluster_ip = "None" } } diff --git a/terraform/modules/apps/mail/postfix.tf b/terraform/modules/apps/mail/postfix.tf index 30d2943..6e72858 100644 --- a/terraform/modules/apps/mail/postfix.tf +++ b/terraform/modules/apps/mail/postfix.tf @@ -20,7 +20,6 @@ resource "kubernetes_secret" "bcc_map" { } } - resource "kubernetes_deployment" "postfix" { metadata { namespace = kubernetes_namespace.mail.metadata[0].name @@ -37,7 +36,7 @@ resource "kubernetes_deployment" "postfix" { } } strategy { - type = "Recreate" + type = "RollingUpdate" } template { metadata { @@ -57,7 +56,6 @@ resource "kubernetes_deployment" "postfix" { image = "tozd/postfix:${var.postfix_tag}" port { container_port = 465 - host_port = 465 } dynamic "env" { for_each = local.postfix_env_vars @@ -177,7 +175,7 @@ resource "kubernetes_deployment" "postfix" { resource "kubernetes_service" "postfix" { metadata { namespace = kubernetes_namespace.mail.metadata[0].name - name = "postfix" + name = "smtps" } spec { @@ -191,7 +189,8 @@ resource "kubernetes_service" "postfix" { target_port = 465 } - type = "LoadBalancer" + type = "ClusterIP" + cluster_ip = "None" } lifecycle { diff --git a/terraform/modules/apps/mail/resources/postfix/stunnel.conf b/terraform/modules/apps/mail/resources/postfix/stunnel.conf index c06a114..cd15bc0 100644 --- a/terraform/modules/apps/mail/resources/postfix/stunnel.conf +++ b/terraform/modules/apps/mail/resources/postfix/stunnel.conf @@ -3,5 +3,5 @@ foreground = yes [dovecot-auth] client = yes accept = 127.0.0.1:31000 -connect = dovecot-auth.mail.svc.cluster.local:31000 +connect = auth.mail.svc.cluster.local:31000 CAfile = /etc/ssl/certs/ca.pem diff --git a/terraform/modules/apps/mail/stunnel.tf b/terraform/modules/apps/mail/stunnel.tf index e882d76..493586b 100644 --- a/terraform/modules/apps/mail/stunnel.tf +++ b/terraform/modules/apps/mail/stunnel.tf @@ -1,3 +1,6 @@ +# This file defines the configuration for stunnel in the mail module. + +# Creates a Kubernetes ConfigMap for stunnel configuration for Dovecot. resource "kubernetes_config_map" "stunnel_dovecot" { metadata { name = "stunnel-dovecot" @@ -8,6 +11,7 @@ resource "kubernetes_config_map" "stunnel_dovecot" { } } +# Creates a Kubernetes ConfigMap for stunnel configuration for Postfix. resource "kubernetes_config_map" "stunnel_postfix" { metadata { name = "stunnel-postfix" @@ -18,6 +22,7 @@ resource "kubernetes_config_map" "stunnel_postfix" { } } +# Creates a Kubernetes manifest for the stunnel certificate using cert-manager. resource "kubernetes_manifest" "stunnel_cert" { manifest = { apiVersion = "cert-manager.io/v1" @@ -38,6 +43,7 @@ resource "kubernetes_manifest" "stunnel_cert" { } } +# Creates a Kubernetes ConfigMap for the CA certificate. resource "kubernetes_config_map" "ca_pem" { metadata { name = "ca-pem" @@ -47,3 +53,4 @@ resource "kubernetes_config_map" "ca_pem" { "ca.pem" = var.ca_pem } } + diff --git a/terraform/modules/apps/nextcloud/ingress.tf b/terraform/modules/apps/nextcloud/ingress.tf index 958f055..0cefa31 100644 --- a/terraform/modules/apps/nextcloud/ingress.tf +++ b/terraform/modules/apps/nextcloud/ingress.tf @@ -11,6 +11,7 @@ resource "kubernetes_service" "nextcloud_apache" { selector = { app = "nextcloud" } + type = "ClusterIP" cluster_ip = "None" } } diff --git a/terraform/modules/apps/nextcloud/redis.tf b/terraform/modules/apps/nextcloud/redis.tf index 63da2f6..6caa25f 100644 --- a/terraform/modules/apps/nextcloud/redis.tf +++ b/terraform/modules/apps/nextcloud/redis.tf @@ -11,6 +11,8 @@ resource "kubernetes_service" "nextcloud_redis" { selector = { app = "redis" } + + type = "ClusterIP" cluster_ip = "None" } } diff --git a/terraform/modules/apps/nginx-reverse-proxy/main.tf b/terraform/modules/apps/nginx-reverse-proxy/main.tf index 4352594..6417cc0 100644 --- a/terraform/modules/apps/nginx-reverse-proxy/main.tf +++ b/terraform/modules/apps/nginx-reverse-proxy/main.tf @@ -45,6 +45,8 @@ resource "kubernetes_service" "reverse-proxy" { selector = { app = "reverse-proxy" } + + type = "ClusterIP" cluster_ip = "None" } } @@ -234,7 +236,7 @@ resource "kubernetes_deployment" "reverse_proxy" { } spec { dynamic "container" { - for_each = local.wireguard_config != "null" ? [1] : [] + for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : [] content { name = "wireguard" @@ -263,6 +265,7 @@ resource "kubernetes_deployment" "reverse_proxy" { capabilities { add = ["NET_ADMIN"] } + read_only_root_filesystem = true } env { @@ -291,11 +294,16 @@ resource "kubernetes_deployment" "reverse_proxy" { mount_path = "/lib/modules" read_only = true } + + volume_mount { + name = "wireguard-run" + mount_path = "/run" + } } } dynamic "container" { - for_each = var.auth_token != "" ? [1] : [] + for_each = nonsensitive(var.auth_token) != "" ? [1] : [] content { name = "auth-sidecar" image = "python:3.11-slim" @@ -322,6 +330,14 @@ resource "kubernetes_deployment" "reverse_proxy" { container_port = 5000 name = "auth" } + + security_context { + read_only_root_filesystem = true + run_as_group = 1000 + run_as_user = 1000 + allow_privilege_escalation = false + run_as_non_root = true + } } } @@ -338,6 +354,7 @@ resource "kubernetes_deployment" "reverse_proxy" { security_context { allow_privilege_escalation = false + read_only_root_filesystem = true } readiness_probe { @@ -386,32 +403,31 @@ resource "kubernetes_deployment" "reverse_proxy" { protocol = upper(port.value.protocol) } } - volume_mount { name = "nginx" mount_path = "/etc/nginx/nginx.conf" sub_path = "nginx.conf" read_only = true } - volume_mount { name = "services" mount_path = "/etc/nginx/conf.d/" read_only = true } - volume_mount { name = "streams" mount_path = "/etc/nginx/streams.d/" read_only = true } - volume_mount { name = "nginx-errors" mount_path = "/usr/share/nginx/html/errors" read_only = true } - + volume_mount { + name = "nginx-tmp" + mount_path = "/tmp" + } dynamic "volume_mount" { for_each = length([for v in var.services : v.tls if v.tls == true]) > 0 ? [1] : [] content { @@ -423,17 +439,17 @@ resource "kubernetes_deployment" "reverse_proxy" { } dynamic "volume" { - for_each = local.wireguard_config != "null" ? [1] : [] + for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : [] content { name = "wireguard-config" config_map { - name = kubernetes_config_map.wireguard_config[0].metadata[0].name + name = nonsensitive(kubernetes_config_map.wireguard_config[0].metadata[0].name) } } } dynamic "volume" { - for_each = local.wireguard_config != "null" ? [1] : [] + for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : [] content { name = "lib-modules" host_path { @@ -442,6 +458,16 @@ resource "kubernetes_deployment" "reverse_proxy" { } } + dynamic "volume" { + for_each = nonsensitive(local.wireguard_config) != "null" ? [1] : [] + content { + name = "wireguard-run" + empty_dir { + medium = "Memory" + } + } + } + volume { name = "auth-script" config_map { @@ -477,6 +503,12 @@ resource "kubernetes_deployment" "reverse_proxy" { } } + volume { + name = "nginx-tmp" + empty_dir { + } + } + dynamic "volume" { for_each = length([for v in var.services : v.tls if v.tls == true]) > 0 ? [1] : [] content { diff --git a/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/nginx.conf b/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/nginx.conf index 4f1f0c0..06ad645 100644 --- a/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/nginx.conf +++ b/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/nginx.conf @@ -1,6 +1,6 @@ worker_processes auto; -error_log /var/log/nginx/error.log notice; +error_log /dev/stderr warn; pid /tmp/nginx.pid; events { @@ -25,7 +25,7 @@ http { '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /var/log/nginx/access.log main; + access_log /dev/stdout main; sendfile on; @@ -43,5 +43,6 @@ http { include /etc/nginx/conf.d/*.conf; } -include /etc/nginx/streams.d/*.conf; - +stream { + include /etc/nginx/streams.d/*.conf; +} \ No newline at end of file diff --git a/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/streams.d/stream.conf.tpl b/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/streams.d/stream.conf.tpl index d7aba8d..1dbb88c 100644 --- a/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/streams.d/stream.conf.tpl +++ b/terraform/modules/apps/nginx-reverse-proxy/resources/nginx/streams.d/stream.conf.tpl @@ -1,15 +1,13 @@ -stream { - upstream ${name} { +upstream ${name} { %{ if resolver != "" ~} - resolver ${resolver}; + resolver ${resolver}; %{ endif ~} - server ${upstream}:${upstream_port}; - } - server { - listen %{ if protocol == "UDP" ~}${port} udp;%{ else ~}${port};%{ endif } + server ${upstream}:${upstream_port}; +} +server { + listen %{ if protocol == "UDP" ~}${port} udp;%{ else ~}${port};%{ endif } %{ if custom_snippet != "" ~} ${custom_snippet} %{ endif ~} - proxy_pass ${name}; - } + proxy_pass ${name}; } diff --git a/terraform/modules/apps/nginx/main.tf b/terraform/modules/apps/nginx/main.tf index ac80fc8..91245bb 100644 --- a/terraform/modules/apps/nginx/main.tf +++ b/terraform/modules/apps/nginx/main.tf @@ -45,6 +45,8 @@ resource "kubernetes_service" "website" { selector = { app = format("website-%s", replace(each.key, ".", "-")) } + + type = "ClusterIP" cluster_ip = "None" } } @@ -177,11 +179,6 @@ resource "kubernetes_deployment" "website" { spec { service_account_name = kubernetes_service_account.website_service_account.metadata[0].name - security_context { - fs_group = 1000 - run_as_user = 1000 - } - container { name = "website" image = "nginx:${var.tag}" @@ -212,7 +209,10 @@ resource "kubernetes_deployment" "website" { } security_context { + run_as_user = 1000 + run_as_group = 1000 allow_privilege_escalation = false + read_only_root_filesystem = true } port { @@ -239,6 +239,10 @@ resource "kubernetes_deployment" "website" { sub_path = "default.conf" read_only = true } + volume_mount { + name = "tmp" + mount_path = "/tmp" + } volume_mount { name = "website" mount_path = "/tmp/site" @@ -265,6 +269,12 @@ resource "kubernetes_deployment" "website" { name = kubernetes_config_map.nginx_default_config[each.key].metadata[0].name } } + volume { + name = "tmp" + empty_dir { + medium = "Memory" + } + } volume { name = "website" host_path { @@ -296,4 +306,3 @@ resource "kubernetes_deployment" "website" { ignore_changes = [spec[0].template[0].metadata[0].annotations["kubectl.kubernetes.io/restartedAt"]] } } - diff --git a/terraform/modules/apps/nginx/resources/nginx.conf b/terraform/modules/apps/nginx/resources/nginx.conf index c258d44..3d0e6f2 100644 --- a/terraform/modules/apps/nginx/resources/nginx.conf +++ b/terraform/modules/apps/nginx/resources/nginx.conf @@ -1,9 +1,8 @@ worker_processes auto; -error_log /var/log/nginx/error.log notice; +error_log /dev/stderr warn; pid /tmp/nginx.pid; - events { worker_connections 1024; } @@ -15,6 +14,10 @@ http { uwsgi_temp_path /tmp/uwsgi_temp; scgi_temp_path /tmp/scgi_temp; + client_max_body_size 10M; + proxy_buffering off; + proxy_request_buffering off; + include /etc/nginx/mime.types; default_type application/octet-stream; @@ -22,7 +25,7 @@ http { '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /var/log/nginx/access.log main; + access_log /dev/stdout main; sendfile on; diff --git a/terraform/modules/apps/open-webui/webui.tf b/terraform/modules/apps/open-webui/webui.tf index 6749423..4a4b9df 100644 --- a/terraform/modules/apps/open-webui/webui.tf +++ b/terraform/modules/apps/open-webui/webui.tf @@ -97,6 +97,7 @@ resource "kubernetes_service" "openwebui" { target_port = 8080 } + type = "ClusterIP" cluster_ip = "None" } diff --git a/terraform/modules/apps/rustdesk/main.tf b/terraform/modules/apps/rustdesk/main.tf index bd7aa2c..774f2d5 100644 --- a/terraform/modules/apps/rustdesk/main.tf +++ b/terraform/modules/apps/rustdesk/main.tf @@ -57,7 +57,7 @@ resource "kubernetes_deployment" "rustdesk_deploy" { } strategy { - type = "Recreate" + type = "RollingUpdate" } template { @@ -72,8 +72,9 @@ resource "kubernetes_deployment" "rustdesk_deploy" { automount_service_account_token = false container { - name = "rustdesk-container" - image = "rustdesk/rustdesk-server-s6:${local.rustdesk_version}" + name = "rustdesk-container" + image = "rustdesk/rustdesk-server-s6:${local.rustdesk_version}" + image_pull_policy = "Always" env_from { config_map_ref { @@ -83,33 +84,30 @@ resource "kubernetes_deployment" "rustdesk_deploy" { security_context { allow_privilege_escalation = false + read_only_root_filesystem = true } port { name = "tcp-port-1" container_port = 21115 - host_port = 21115 protocol = "TCP" } port { name = "tcp-port-2" container_port = 21116 - host_port = 21116 protocol = "TCP" } port { name = "udp-port-1" container_port = 21116 - host_port = 21116 protocol = "UDP" } port { name = "tcp-port-3" container_port = 21117 - host_port = 21117 protocol = "TCP" } @@ -131,6 +129,11 @@ resource "kubernetes_deployment" "rustdesk_deploy" { sub_path = "id_ed25519.pub" read_only = true } + + volume_mount { + name = "rust-run" + mount_path = "/run" + } } volume { @@ -146,6 +149,13 @@ resource "kubernetes_deployment" "rustdesk_deploy" { secret_name = kubernetes_secret.rustdesk_keys.metadata[0].name } } + + volume { + name = "rust-run" + empty_dir { + medium = "Memory" + } + } } } } @@ -153,7 +163,7 @@ resource "kubernetes_deployment" "rustdesk_deploy" { resource "kubernetes_service" "rustdesk_tcp_ports" { metadata { - name = "rustdesk-tcp-ports" + name = "tcp" namespace = kubernetes_namespace.rustdesk.metadata[0].name } @@ -180,7 +190,7 @@ resource "kubernetes_service" "rustdesk_tcp_ports" { target_port = 21117 } - type = "LoadBalancer" + type = "ClusterIP" } lifecycle { @@ -193,7 +203,7 @@ resource "kubernetes_service" "rustdesk_tcp_ports" { resource "kubernetes_service" "rustdesk_udp_ports" { metadata { - name = "rustdesk-udp-ports" + name = "udp" namespace = kubernetes_namespace.rustdesk.metadata[0].name } @@ -209,7 +219,7 @@ resource "kubernetes_service" "rustdesk_udp_ports" { protocol = "UDP" } - type = "LoadBalancer" + type = "ClusterIP" } lifecycle { diff --git a/terraform/modules/apps/sftpgo/main.tf b/terraform/modules/apps/sftpgo/main.tf index e76ade5..fd562fe 100644 --- a/terraform/modules/apps/sftpgo/main.tf +++ b/terraform/modules/apps/sftpgo/main.tf @@ -255,6 +255,8 @@ resource "kubernetes_service" "sftpgo_webdav" { port = var.tls_enabled ? 443 : 80 target_port = "dav" } + + type = "ClusterIP" cluster_ip = "None" } } @@ -273,6 +275,8 @@ resource "kubernetes_service" "sftpgo_web" { port = var.tls_enabled ? 443 : 80 target_port = "web" } - type = "ClusterIP" + + type = "ClusterIP" + cluster_ip = "None" } } diff --git a/terraform/modules/apps/template/main.tf b/terraform/modules/apps/template/main.tf index 7cd54a6..5569150 100644 --- a/terraform/modules/apps/template/main.tf +++ b/terraform/modules/apps/template/main.tf @@ -148,6 +148,7 @@ resource "kubernetes_service" "app" { target_port = 21115 } + type = "ClusterIP" cluster_ip = "None" } diff --git a/terraform/modules/db/mariadb/main.tf b/terraform/modules/db/mariadb/main.tf index a8e09cc..093e31d 100644 --- a/terraform/modules/db/mariadb/main.tf +++ b/terraform/modules/db/mariadb/main.tf @@ -41,6 +41,16 @@ resource "kubernetes_config_map" "ssl_config" { } } +resource "kubernetes_config_map" "backup_script" { + metadata { + name = "${var.app_name}-sql-backup-script" + namespace = var.namespace + } + data = { + "backup.sh" = file("${path.module}/resources/backup.sh") + } +} + resource "kubernetes_service_account" "service_account" { metadata { @@ -239,7 +249,6 @@ resource "kubernetes_deployment" "deployment" { } } -# TODO: This should move out of here resource "kubernetes_cron_job_v1" "backup_data_cron" { metadata { name = "mariadb-backup-job" @@ -289,25 +298,50 @@ resource "kubernetes_cron_job_v1" "backup_data_cron" { name = "MARIADB_DATABASE" value = var.app_name } + env { + name = "APP_NAME" + value = var.app_name + } + env { + name = "BACKUP_RETENTION" + value = var.retention_days + } security_context { allow_privilege_escalation = false } command = ["/bin/sh", "-c"] - args = [join(";", [ - "/usr/bin/mariadb-dump --single-transaction -h mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE | gzip > /backups/${var.app_name}-sql-`date +\"%Y%m%d\"`.sql.gz", - "find /backups -type f -name '${var.app_name}-sql-*.sql.gz' -mtime +${var.retention_days} | xargs --no-run-if-empty rm" - ])] + args = ["/tmp/scripts/backup.sh"] volume_mount { - mount_path = "/backups" - name = "backups-storage" + mount_path = "/backup" + name = "backup-storage" } + volume_mount { + name = "backup-script" + mount_path = "/tmp/scripts" + read_only = true + } + volume_mount { + name = "tmp" + mount_path = "/tmp" + } } volume { - name = "backups-storage" + name = "backup-storage" host_path { path = var.backup_folder } } + volume { + name = "backup-script" + config_map { + name = kubernetes_config_map.backup_script.metadata[0].name + default_mode = "0755" + } + } + volume { + name = "tmp" + empty_dir {} + } restart_policy = "Never" termination_grace_period_seconds = 30 } diff --git a/terraform/modules/db/mariadb/resources/backup.sh b/terraform/modules/db/mariadb/resources/backup.sh new file mode 100644 index 0000000..a08da87 --- /dev/null +++ b/terraform/modules/db/mariadb/resources/backup.sh @@ -0,0 +1,20 @@ +#!/bin/sh +if [ -z "$MARIADB_USER" ] || [ -z "$MARIADB_PASSWORD" ] || [ -z "$MARIADB_DATABASE" ]; then + echo "MARIADB_USER, MARIADB_PASSWORD and MARIADB_DATABASE must be set" + exit 1 +fi +if [ -z "$APP_NAME" ]; then + echo "APP_NAME must be set" + exit 1 +fi +if [ -z "$BACKUP_RETENTION" ]; then + echo "BACKUP_RETENTION must be set" + exit 1 +fi + +echo "Creating backup of MariaDB database for app: $APP_NAME" +/usr/bin/mariadb-dump --single-transaction -h mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE | gzip > /backup/$APP_NAME-sql-`date +"%Y%m%d"`.sql.gz + +BACKUP_FILE_PATTERN="$APP_NAME-sql-*.sql.gz" +echo "Removing old backups matching pattern: $BACKUP_FILE_PATTERN" +find /backup -type f -name "$BACKUP_FILE_PATTERN" -mtime +$BACKUP_RETENTION | xargs --no-run-if-empty rm diff --git a/terraform/modules/utils/scw_rclone/resources/backup.sh b/terraform/modules/utils/scw_rclone/resources/backup.sh index 5669730..29a8cd2 100644 --- a/terraform/modules/utils/scw_rclone/resources/backup.sh +++ b/terraform/modules/utils/scw_rclone/resources/backup.sh @@ -27,7 +27,7 @@ unset SCW_SECRET_KEY # Create backup echo "Creating backup of /src directory" -tar -zcvpf /backup/$APP_NAME-files-`date +\"%Y%m%d\"`.tar.gz /src +tar -zcvpf /backup/$APP_NAME-files-`date +"%Y%m%d"`.tar.gz /src # Remove old backups BACKUP_FILE_PATTERN="$APP_NAME-files-*.tar.gz"