From 3443452cf7827fa99aefbd6235b8e31ed6c8506a Mon Sep 17 00:00:00 2001 From: WrenIX Date: Wed, 29 May 2024 09:08:58 +0200 Subject: [PATCH] feat(mycloud-stalwart-mail): init - WIP --- base-values/mycloud-mail-stalwart.yaml | 17 ++ mycloud-mail-stalwart/.helmignore | 23 ++ mycloud-mail-stalwart/Chart.yaml | 9 + .../templates/authentik-application.yaml | 58 ++++ .../templates/configmap_init_crd.yaml | 13 + mycloud-mail-stalwart/templates/release.yaml | 258 ++++++++++++++++++ mycloud-mail-stalwart/templates/secret.yaml | 9 + mycloud-mail-stalwart/values.yaml | 127 +++++++++ 8 files changed, 514 insertions(+) create mode 100644 base-values/mycloud-mail-stalwart.yaml create mode 100644 mycloud-mail-stalwart/.helmignore create mode 100644 mycloud-mail-stalwart/Chart.yaml create mode 100644 mycloud-mail-stalwart/templates/authentik-application.yaml create mode 100644 mycloud-mail-stalwart/templates/configmap_init_crd.yaml create mode 100644 mycloud-mail-stalwart/templates/release.yaml create mode 100644 mycloud-mail-stalwart/templates/secret.yaml create mode 100644 mycloud-mail-stalwart/values.yaml diff --git a/base-values/mycloud-mail-stalwart.yaml b/base-values/mycloud-mail-stalwart.yaml new file mode 100644 index 0000000..ea34236 --- /dev/null +++ b/base-values/mycloud-mail-stalwart.yaml @@ -0,0 +1,17 @@ +## +# commons are from mycloud-core +## + +components: + mycloud-services: + # patch mycloud-core to get another database + values: + databases: + mycloud-mail-stalwart: + type: postgresql + + mycloud-stalwart-mail: + enabled: true + namespace: + # current namespace + name: diff --git a/mycloud-mail-stalwart/.helmignore b/mycloud-mail-stalwart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/mycloud-mail-stalwart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/mycloud-mail-stalwart/Chart.yaml b/mycloud-mail-stalwart/Chart.yaml new file mode 100644 index 0000000..7becfff --- /dev/null +++ b/mycloud-mail-stalwart/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: mycloud-mail-stalwart +description: myCloud component to setup stalwart mail-server +type: application +maintainers: + - name: WrenIX + url: https://wrenix.eu + +version: 0.1.0 diff --git a/mycloud-mail-stalwart/templates/authentik-application.yaml b/mycloud-mail-stalwart/templates/authentik-application.yaml new file mode 100644 index 0000000..958f113 --- /dev/null +++ b/mycloud-mail-stalwart/templates/authentik-application.yaml @@ -0,0 +1,58 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: GitRepository +metadata: + name: wrenix-helm-charts +spec: + url: https://codeberg.org/wrenix/helm-charts.git + ref: + branch: "authentik-application/ldap" + interval: 10m +--- +apiVersion: helm.toolkit.fluxcd.io/v2beta2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-auth +spec: + chart: + spec: + sourceRef: + kind: GitRepository + name: "wrenix-helm-charts" + # namespace: "flux-system" + chart: "./authentik-application" + reconcileStrategy: "Revision" + install: + {{- toYaml .Values.commons.helm.release.install | nindent 4 }} + test: + {{- toYaml .Values.commons.helm.release.test | nindent 4 }} + upgrade: + {{- toYaml .Values.commons.helm.release.upgrade | nindent 4 }} + driftDetection: + {{- toYaml .Values.commons.helm.release.driftDetection | nindent 4 }} + interval: 10m + values: + {{- $host := .Values.ingress.host | default (printf "mail.%s" .Values.commons.ingress.domain) }} + blueprint: + authentik: + domain: "https://{{ .Values.commons.auth.host | default (printf "auth.%s" .Values.commons.ingress.domain) }}" + provider: + type: "ldap" + name: "Mail-Stalwart" + ldap: + token: {{ .Values.auth.LDAPToken | default (derivePassword 1 "long" .Values.commons.masterPassword "stalwart-mail" "auth.token") | quote }} + + groups: + - slug: "mycloud - users" + bindID: "4525d9a3-1853-45dc-adc0-6d411a3a907e" + + application: + policyEngineMode: "any" + openInNewTab: true + publisher: "WrenIX's myCloud" + slug: "mycloud-mail-stalwart" + group: "Communication" + name: "Mail Stalwart" + launchURL: "https://{{ $host }}/" + icon: "https://{{ $host }}/logo.svg" + description: "Unlock the future of email with Stalwart (Management)" diff --git a/mycloud-mail-stalwart/templates/configmap_init_crd.yaml b/mycloud-mail-stalwart/templates/configmap_init_crd.yaml new file mode 100644 index 0000000..71c8325 --- /dev/null +++ b/mycloud-mail-stalwart/templates/configmap_init_crd.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-init + namespace: "{{ .Values.init.namespace }}" +data: + {{- if and + (.Capabilities.APIVersions.Has "v1/ConfigMap") + }} + init: "-1" + {{- else }} + init: "{{ add1 .Values.init.version }}" + {{- end }} diff --git a/mycloud-mail-stalwart/templates/release.yaml b/mycloud-mail-stalwart/templates/release.yaml new file mode 100644 index 0000000..7e49820 --- /dev/null +++ b/mycloud-mail-stalwart/templates/release.yaml @@ -0,0 +1,258 @@ +--- +apiVersion: helm.toolkit.fluxcd.io/v2beta2 +kind: HelmRelease +metadata: + name: "{{ .Release.Name }}-hr" +spec: + chart: + spec: + sourceRef: + kind: GitRepository + name: "wrenix-helm-charts" + namespace: "flux-system" + chart: "./stalwart-mail" + reconcileStrategy: "Revision" + install: + {{- toYaml .Values.commons.helm.release.install | nindent 4 }} + test: + {{- toYaml .Values.commons.helm.release.test | nindent 4 }} + upgrade: + {{- toYaml .Values.commons.helm.release.upgrade | nindent 4 }} + driftDetection: + {{- toYaml .Values.commons.helm.release.driftDetection | nindent 4 }} + interval: 10m + valuesFrom: + - kind: Secret + name: {{ .Release.Name | quote }} + valuesKey: admin_password + targetPath: "secrets.env.FALLBACK_ADMIN_SECRET" + - kind: Secret + name: {{ .Release.Name | quote }} + valuesKey: "database_password" + targetPath: "secrets.env.STORE_PGSQL_PASSWORD" + - kind: Secret + name: {{ .Release.Name | quote }} + valuesKey: "metrics_secret" + targetPath: "secrets.env.METRICS_SECRET" + values: + {{- $host := .Values.ingress.host | default (printf "mail.%s" .Values.commons.ingress.domain) }} + config: + + lookup: + default: + hostname: {{ $host | quote }} + + server: + + listener: + smtp: + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + submission: + submissions: + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + imap: + imaptls: + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + pop3: + pop3s: + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + sieve: + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + + # without proxy and tls for ingress + http: + protocol: "http" + bind: [ "[::]:8080" ] + + https: + url: {{ printf "https://%s" $host | quote }} + bind: [ "[::]:443" ] + proxy: + trusted-networks: + {{- toYaml .Values.networks.trustedNetworks | nindent 16 }} + tls: + implicit: true + + storage: + data: "pgsql" + fts: "pgsql" + full-text: + default-language: "en" + blob: "filesystem" + lookup: "pgsql" + directory: "ldap" + + store: + rocksdb: null + pgsql: + type: "postgresql" + host: {{ .Values.database.host | quote }} + database: {{ .Values.database.name | quote }} + user: {{ .Values.database.username | quote }} + password: "%{env:STORE_PGSQL_PASSWORD}%" + filesystem: + type: "fs" + path: "/data/blobs" + depth: 2 + + directory: + internal: + ldap: + type: "ldap" + url: "ldap://{{ .Release.Name }}-auth-authentik-application-ldap:389" + base-dn: "dc=ldap,dc=goauthentik,dc=io" + timeout: "30s" + tls: + enable: false + allow-invalid-certs: false + bind: + dn: "cn=ldap-mail,ou=users,dc=ldap,dc=goauthentik,dc=io" + secret: "oJyh5W3P50glb8fWDdlDABUJlJPIMHp4dGBl14g9aLxv1SNbLudvfBWFMrFJ" + auth: + enable: false + dn: "cn=?,ou=users,dc=ldap,dc=goauthentik,dc=io" + search: true + filter: + name: "(&(|(objectClass=posixAccount)(ak-active=TRUE))(cn=?))" + email: "(&(|(objectClass=posixAccount)(ak-active=TRUE))(|(mail=?)(mailAlias=?)(mailList=?)))" + verify: "(&(|(objectClass=posixAccount)(ak-active=TRUE))(|(mail=*?*)(mailAlias=*?*)))" + expand: "(&(|(objectClass=posixAccount)(ak-active=TRUE))(mailList=?))" + domains: "(&(|(objectClass=posixAccount)(ak-active=TRUE))(|(mail=*@?)(mailAlias=*@?)))" + attributes: + name: "cn" + class: "ak-superuser" + description: "displayName" + # secret: "userPassword" + groups: "memberOf" + email: "mail" + email-alias: "mailAlias" + # quota: "diskQuota" + + tracer: + stdout: + level: info + # TODO cleanup + # level: warn + {{- with .Values.commons.tracing }} + {{- if .enabled }} + otel: + enable: + span-exporter: true + log-exporter: false + level: "debug" + {{- if .grpc.enabled }} + transport: "grpc" + endpoint: {{ printf "%s://%s" (.grpc.insecure | ternary "http" "https") .grpc.endpoint }} + {{- else }} + transport: "http" + endpoint: {{ .hrrp.endpoint }} + {{- end }} + {{- end }} + {{- end }} + + certificate: + default: + cert: "%{file:/opt/stalwart-mail/etc/certs/tls.crt}%" + private-key: "%{file:/opt/stalwart-mail/etc/certs/tls.key}%" + + service: + {{- if .Values.networks.ipv6 }} + ipFamilies: [ "IPv6", "IPv4" ] + ipFamilyPolicy: "RequireDualStack" + {{- end }} + ports: + submission: + imap: + pop3: + http: 8080 + + ingress: + enabled: true + annotations: + {{- with .Values.commons.ingress.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + hosts: + - host: "{{ .Values.commons.ingress.domain }}" + paths: + - path: /.well-known/jmap + pathType: Prefix + - path: /.well-known/mta-sts.txt + pathType: Exact + - path: /.well-known/mail-v1.xml + pathType: Exact + - path: /.well-known/autoconfig + pathType: Prefix + - path: /autodiscover + pathType: Prefix + - host: "autoconfig.{{ .Values.commons.ingress.domain }}" + paths: + - path: /mail + pathType: Prefix + - host: "autodiscover.{{ .Values.commons.ingress.domain }}" + paths: + - path: /autodiscover + pathType: Prefix + - host: "mta-sts.{{ .Values.commons.ingress.domain }}" + paths: + - path: / + pathType: Prefix + {{- if .Values.commons.ingress.tls.enabled }} + tls: + {{- with .Values.commons.ingress.tls.override }} + {{- toYaml . | nindent 8 }} + {{- else }} + - secretName: "{{ .Release.Name }}-cert" + hosts: + - "{{ .Values.commons.ingress.domain }}" + - "autoconfig.{{ .Values.commons.ingress.domain }}" + - "autodiscover.{{ .Values.commons.ingress.domain }}" + - "mta-sts.{{ .Values.commons.ingress.domain }}" + {{- end }} + {{- end }} + + traefik: + enabled: true + host: {{ $host | quote }} + ports: + smtp: + match: 'HostSNI(`*`)' + submission: + imap: + pop3: + https: + entrypoint: websecure + + certificate: + certmanager: + dnsNames: + - {{ $host | quote }} + + prometheus: + servicemonitor: + enabled: {{ (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1/ServiceMonitor") }} + labels: + {{- toYaml .Values.commons.prometheus.monitor.labels | nindent 10 }} + + persistence: + enabled: true + size: {{ .Values.persistence.size }} + {{- with .Values.persistence.storageClass | default .Values.commons.persistence.storageClass }} + storageClass: {{ . }} + {{- end }} + {{- if .Values.commons.persistence.hostPath.enabled }} + hostPath: "{{ .Values.commons.persistence.hostPath.prefix }}/mail-stalwart" + {{- end }} diff --git a/mycloud-mail-stalwart/templates/secret.yaml b/mycloud-mail-stalwart/templates/secret.yaml new file mode 100644 index 0000000..4450d88 --- /dev/null +++ b/mycloud-mail-stalwart/templates/secret.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ .Release.Name }}" +data: + admin_password: {{ .Values.admin.password | default (derivePassword 1 "long" .Values.commons.masterPassword "mail-stalwart" "admin_password" | b64enc) | b64enc }} + database_password: {{ .Values.database.password | default (derivePassword 1 "long" .Values.commons.masterPassword "mail-stalwart" "database_password" | b64enc) | b64enc }} + metrics_secret: {{ derivePassword 1 "long" .Values.commons.masterPassword "stalwart-mail" "metrics_secret" | b64enc }} diff --git a/mycloud-mail-stalwart/values.yaml b/mycloud-mail-stalwart/values.yaml new file mode 100644 index 0000000..0094351 --- /dev/null +++ b/mycloud-mail-stalwart/values.yaml @@ -0,0 +1,127 @@ +init: + version: 0 + namespace: "bases" + +commons: + # -- masterPassword to generate secrets + # @section -- Commons + masterPassword: "CHANGEME" + + auth: + # -- default auth.(.Values.commons.ingress.domain) + # @section -- Commons + host: + + theme: + # -- title everywhere + # @section -- Commons theme + title: myCloud + # -- logo everywhere + # @section -- Commons theme + logo: /static/dist/assets/icons/icon_left_brand.svg + # -- favicon everywhere + # @section -- Commons theme + favicon: /static/dist/assets/icons/icon.png + + persistence: + # -- storageClass of PVC + # @section -- Commons Persistence + storageClass: + hostPath: + # -- use hostPath instatt of PVC + # @section -- Commons Persistence + enabled: false + # -- use hostPath under the following path + # @section -- Commons Persistence + prefix: "/var/lib/mycloud" + + helm: + release: + # -- install of FluxCD HelmRelease + # @section -- Commons helm release + install: {} + # -- test of FluxCD HelmRelease + # @section -- Commons helm release + test: {} + # -- upgrade of FluxCD HelmRelease + # @section -- Commons helm release + upgrade: {} + # -- driftDetection of FluxCD HelmRelease + # @section -- Commons helm release + driftDetection: {} + + ingress: + # -- top domain for all services + # @section -- Commons Ingress + domain: "wrenix.eu" + # -- annotations for all ingress objects + # @section -- Commons Ingress + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + tls: + # -- tls on every ingress + # @section -- Commons Ingress + enabled: true + # -- use own definition of tls (e.g. for own or wildcard certificate) + # @section -- Commons Ingress + override: [] + + prometheus: + monitor: + # -- labels on Pod- and Service-Monitor + # @section -- Commons Monitoring + labels: {} + rules: + # -- labels on PrometheusRules + # @section -- Commons Monitoring + labels: {} + + tracing: + # -- enable tracing on all components + # @section -- Commons Tracing + enabled: false + http: + # -- http endpoint + # @section -- Commons Tracing + endpoint: "http://tempo.monitoring.svc:4318/v1/traces" + grpc: + # -- prefer grpc over http + # @section -- Commons Tracing + enabled: true + # -- allow insecure connection per grpc + # @section -- Commons Tracing + insecure: true + # -- grpc endpoint + # @section -- Commons Tracing + endpoint: "tempo.monitoring.svc:4317" + +auth: + # -- generated by .Values.commons.masterPassword + LDAPToken: + +admin: + # -- fallback admin password (default: generated by .Values.commons.masterPassword) + password: + +networks: + ipv6: false + trustedNetworks: + - "127.0.0.0/8" + - "::1" + - "10.0.0.0/8" + +ingress: + # -- used for main domain + host: + +database: + # -- default is from mysql-services + host: mycloud-services-postgresql + name: mail-stalwart + username: mail-stalwart + # -- generated by .Values.commons.masterPassword (equal to mycloud-services) + password: + +persistence: + storageClass: + size: 16Gi