diff --git a/kubernetes/apps/selfhosted/email-oauth2-proxy/app/configmap.yaml b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/configmap.yaml new file mode 100644 index 000000000..02a6ea384 --- /dev/null +++ b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/configmap.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: email-oauth2-proxy-config +data: + emailproxy.config: | + [Email OAuth 2.0 Proxy configuration] + # Log to stdout for k8s log collection + delete_account_token_on_password_error = False + encrypt_client_secret_on_first_use = False + + [outlook] + permission_url = https://login.microsoftonline.com/common/oauth2/v2.0/authorize + token_url = https://login.microsoftonline.com/common/oauth2/v2.0/token + oauth2_scope = https://outlook.office.com/IMAP.AccessAsUser.All offline_access + redirect_uri = https://login.microsoftonline.com/common/oauth2/nativeclient + + server_address = outlook.office.com + server_port = 993 + + local_address = 0.0.0.0 + local_port = 1993 diff --git a/kubernetes/apps/selfhosted/email-oauth2-proxy/app/externalsecret.yaml b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/externalsecret.yaml new file mode 100644 index 000000000..bd7507a42 --- /dev/null +++ b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/externalsecret.yaml @@ -0,0 +1,23 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: email-oauth2-proxy +spec: + secretStoreRef: + kind: ClusterSecretStore + name: infisical + target: + name: email-oauth2-proxy-secret + template: + engineVersion: v2 + mergePolicy: Replace + data: + OUTLOOK_ADDRESS: "{{ .STALWART_OUTLOOK_ADDRESS }}" + OUTLOOK_OAUTH_CLIENT_ID: "{{ .STALWART_OUTLOOK_OAUTH_CLIENT_ID }}" + OUTLOOK_OAUTH_CLIENT_SECRET: "{{ .STALWART_OUTLOOK_OAUTH_CLIENT_SECRET }}" + dataFrom: + - find: + name: + regexp: ^STALWART_OUTLOOK.* diff --git a/kubernetes/apps/selfhosted/email-oauth2-proxy/app/helmrelease.yaml b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/helmrelease.yaml new file mode 100644 index 000000000..db2ce3483 --- /dev/null +++ b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/helmrelease.yaml @@ -0,0 +1,85 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s/helm-charts/main/charts/other/app-template/schemas/helmrelease-helm-v2.schema.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: email-oauth2-proxy +spec: + interval: 30m + chartRef: + kind: OCIRepository + name: app-template + install: + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + strategy: rollback + retries: 3 + values: + controllers: + main: + strategy: Recreate + annotations: + reloader.stakater.com/auto: "true" + containers: + app: + image: + repository: blacktirion/email-oauth2-proxy-docker + tag: "2.4.0" + env: + CACHE_STORE: /config/credstore.config + LOGFILE: "true" + envFrom: + - secretRef: + name: email-oauth2-proxy-secret + probes: + liveness: + enabled: true + custom: true + spec: + tcpSocket: + port: &port 1993 + initialDelaySeconds: 10 + periodSeconds: 30 + readiness: + enabled: true + custom: true + spec: + tcpSocket: + port: *port + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi + service: + app: + controller: main + ports: + imap: + port: *port + persistence: + config: + type: configMap + name: email-oauth2-proxy-config + advancedMounts: + main: + app: + - path: /app/emailproxy.config + subPath: emailproxy.config + readOnly: true + data: + type: persistentVolumeClaim + storageClass: ceph-rbd + accessMode: ReadWriteOnce + size: 100Mi + advancedMounts: + main: + app: + - path: /config diff --git a/kubernetes/apps/selfhosted/email-oauth2-proxy/app/kustomization.yaml b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/kustomization.yaml new file mode 100644 index 000000000..31f73407b --- /dev/null +++ b/kubernetes/apps/selfhosted/email-oauth2-proxy/app/kustomization.yaml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./helmrelease.yaml + - ./externalsecret.yaml + - ./configmap.yaml diff --git a/kubernetes/apps/selfhosted/email-oauth2-proxy/ks.yaml b/kubernetes/apps/selfhosted/email-oauth2-proxy/ks.yaml new file mode 100644 index 000000000..fbf0ed968 --- /dev/null +++ b/kubernetes/apps/selfhosted/email-oauth2-proxy/ks.yaml @@ -0,0 +1,30 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/kustomize.toolkit.fluxcd.io/kustomization_v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app email-oauth2-proxy + namespace: &namespace selfhosted +spec: + targetNamespace: *namespace + commonMetadata: + labels: + app.kubernetes.io/name: *app + dependsOn: + - name: stalwart + namespace: selfhosted + - name: external-secrets-stores + namespace: external-secrets + path: ./kubernetes/apps/selfhosted/email-oauth2-proxy/app + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + wait: true + interval: 30m + retryInterval: 1m + timeout: 5m + postBuild: + substitute: + APP: *app diff --git a/kubernetes/apps/selfhosted/imapsync/app/externalsecret.yaml b/kubernetes/apps/selfhosted/imapsync/app/externalsecret.yaml new file mode 100644 index 000000000..653f46869 --- /dev/null +++ b/kubernetes/apps/selfhosted/imapsync/app/externalsecret.yaml @@ -0,0 +1,30 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: imapsync +spec: + secretStoreRef: + kind: ClusterSecretStore + name: infisical + target: + name: imapsync-credentials + template: + engineVersion: v2 + mergePolicy: Replace + data: + # Source provider credentials + GMAIL_ADDRESS: "{{ .STALWART_GMAIL_ADDRESS }}" + gmail-password: "{{ .STALWART_GMAIL_IMAP_PASSWORD }}" + MIGADU_ADDRESS: "{{ .STALWART_MIGADU_ADDRESS }}" + migadu-password: "{{ .STALWART_MIGADU_IMAP_PASSWORD }}" + OUTLOOK_ADDRESS: "{{ .STALWART_OUTLOOK_ADDRESS }}" + outlook-password: "{{ .STALWART_OUTLOOK_IMAP_PASSWORD }}" + # Stalwart destination credentials + STALWART_USER: "{{ .STALWART_PRIMARY_USER }}" + stalwart-password: "{{ .STALWART_PRIMARY_PASSWORD }}" + dataFrom: + - find: + name: + regexp: ^STALWART.* diff --git a/kubernetes/apps/selfhosted/imapsync/app/helmrelease.yaml b/kubernetes/apps/selfhosted/imapsync/app/helmrelease.yaml new file mode 100644 index 000000000..cbf9f0b97 --- /dev/null +++ b/kubernetes/apps/selfhosted/imapsync/app/helmrelease.yaml @@ -0,0 +1,233 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s/helm-charts/main/charts/other/app-template/schemas/helmrelease-helm-v2.schema.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: imapsync +spec: + interval: 30m + chartRef: + kind: OCIRepository + name: app-template + install: + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + strategy: rollback + retries: 3 + values: + controllers: + # ---- Gmail ---- + gmail: + type: cronjob + cronjob: + schedule: "*/10 * * * *" + timeZone: "Etc/UTC" + suspend: true + concurrencyPolicy: Forbid + startingDeadlineSeconds: 300 + successfulJobsHistory: 3 + failedJobsHistory: 5 + activeDeadlineSeconds: 540 + backoffLimit: 2 + pod: + restartPolicy: Never + containers: + app: + image: + repository: gilleslamiral/imapsync + tag: "2.314" + env: + GMAIL_ADDRESS: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: GMAIL_ADDRESS + STALWART_USER: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: STALWART_USER + args: + - --gmail1 + - --host2=stalwart.selfhosted.svc.cluster.local + - --port2=143 + - --user1=$(GMAIL_ADDRESS) + - --passfile1=/secrets/gmail-password + - --user2=$(STALWART_USER) + - --passfile2=/secrets/stalwart-password + - --skipcrossduplicates + - "--exclude=\\[Gmail\\]/(All Mail|Important|Starred|Spam|Chats|Trash)" + - --usecache + - --tmpdir=/cache + - --logdir=/cache/logs + - --maxmessagespersecond=3 + - --errorsmax=200 + - --pidfilelocking + - --pidfile=/cache/gmail.pid + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + # ---- Outlook ---- + outlook: + type: cronjob + cronjob: + schedule: "2-52/10 * * * *" + timeZone: "Etc/UTC" + suspend: true + concurrencyPolicy: Forbid + startingDeadlineSeconds: 300 + successfulJobsHistory: 3 + failedJobsHistory: 5 + activeDeadlineSeconds: 540 + backoffLimit: 2 + pod: + restartPolicy: Never + containers: + app: + image: + repository: gilleslamiral/imapsync + tag: "2.314" + env: + OUTLOOK_ADDRESS: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: OUTLOOK_ADDRESS + STALWART_USER: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: STALWART_USER + args: + - --host1=email-oauth2-proxy.selfhosted.svc.cluster.local + - --port1=1993 + - --host2=stalwart.selfhosted.svc.cluster.local + - --port2=143 + - --user1=$(OUTLOOK_ADDRESS) + - --passfile1=/secrets/outlook-password + - --user2=$(STALWART_USER) + - --passfile2=/secrets/stalwart-password + - --usecache + - --tmpdir=/cache + - --logdir=/cache/logs + - --errorsmax=200 + - --pidfilelocking + - --pidfile=/cache/outlook.pid + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + # ---- Migadu ---- + migadu: + type: cronjob + cronjob: + schedule: "4-54/10 * * * *" + timeZone: "Etc/UTC" + suspend: true + concurrencyPolicy: Forbid + startingDeadlineSeconds: 300 + successfulJobsHistory: 3 + failedJobsHistory: 5 + activeDeadlineSeconds: 540 + backoffLimit: 2 + pod: + restartPolicy: Never + containers: + app: + image: + repository: gilleslamiral/imapsync + tag: "2.314" + env: + MIGADU_ADDRESS: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: MIGADU_ADDRESS + STALWART_USER: + valueFrom: + secretKeyRef: + name: imapsync-credentials + key: STALWART_USER + args: + - --host1=imap.migadu.com + - --port1=993 + - --ssl1 + - --host2=stalwart.selfhosted.svc.cluster.local + - --port2=143 + - --user1=$(MIGADU_ADDRESS) + - --passfile1=/secrets/migadu-password + - --user2=$(STALWART_USER) + - --passfile2=/secrets/stalwart-password + - --usecache + - --tmpdir=/cache + - --logdir=/cache/logs + - --errorsmax=200 + - --pidfilelocking + - --pidfile=/cache/migadu.pid + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + persistence: + # Credentials mounted as files for --passfile + secrets: + type: secret + name: imapsync-credentials + defaultMode: 0400 + advancedMounts: + gmail: + app: + - path: /secrets + readOnly: true + outlook: + app: + - path: /secrets + readOnly: true + migadu: + app: + - path: /secrets + readOnly: true + # Per-provider cache PVCs (RWO -- avoids multi-node mount conflicts) + cache-gmail: + type: persistentVolumeClaim + storageClass: ceph-rbd + accessMode: ReadWriteOnce + size: 1Gi + advancedMounts: + gmail: + app: + - path: /cache + cache-outlook: + type: persistentVolumeClaim + storageClass: ceph-rbd + accessMode: ReadWriteOnce + size: 1Gi + advancedMounts: + outlook: + app: + - path: /cache + cache-migadu: + type: persistentVolumeClaim + storageClass: ceph-rbd + accessMode: ReadWriteOnce + size: 1Gi + advancedMounts: + migadu: + app: + - path: /cache diff --git a/kubernetes/apps/selfhosted/imapsync/app/kustomization.yaml b/kubernetes/apps/selfhosted/imapsync/app/kustomization.yaml new file mode 100644 index 000000000..a530998cf --- /dev/null +++ b/kubernetes/apps/selfhosted/imapsync/app/kustomization.yaml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./helmrelease.yaml + - ./externalsecret.yaml diff --git a/kubernetes/apps/selfhosted/imapsync/ks.yaml b/kubernetes/apps/selfhosted/imapsync/ks.yaml new file mode 100644 index 000000000..baf8c8a1d --- /dev/null +++ b/kubernetes/apps/selfhosted/imapsync/ks.yaml @@ -0,0 +1,32 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/kustomize.toolkit.fluxcd.io/kustomization_v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app imapsync + namespace: &namespace selfhosted +spec: + targetNamespace: *namespace + commonMetadata: + labels: + app.kubernetes.io/name: *app + dependsOn: + - name: stalwart + namespace: selfhosted + - name: email-oauth2-proxy + namespace: selfhosted + - name: external-secrets-stores + namespace: external-secrets + path: ./kubernetes/apps/selfhosted/imapsync/app + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + wait: false + interval: 30m + retryInterval: 1m + timeout: 5m + postBuild: + substitute: + APP: *app diff --git a/kubernetes/apps/selfhosted/kustomization.yaml b/kubernetes/apps/selfhosted/kustomization.yaml index 0d0d73c5d..edc2edd91 100644 --- a/kubernetes/apps/selfhosted/kustomization.yaml +++ b/kubernetes/apps/selfhosted/kustomization.yaml @@ -15,3 +15,6 @@ resources: - ./obsidian-couchdb/ks.yaml - ./resume/ks.yaml - ./inbox-zero/ks.yaml + - ./stalwart/ks.yaml + - ./email-oauth2-proxy/ks.yaml + - ./imapsync/ks.yaml diff --git a/kubernetes/apps/selfhosted/stalwart/app/externalsecret.yaml b/kubernetes/apps/selfhosted/stalwart/app/externalsecret.yaml new file mode 100644 index 000000000..bdebc730d --- /dev/null +++ b/kubernetes/apps/selfhosted/stalwart/app/externalsecret.yaml @@ -0,0 +1,41 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: stalwart +spec: + secretStoreRef: + kind: ClusterSecretStore + name: infisical + target: + name: stalwart-secret + template: + engineVersion: v2 + mergePolicy: Replace + data: + # Admin credentials + FALLBACK_ADMIN_SECRET: "{{ .STALWART_ADMIN_PASSWORD }}" + # Prometheus metrics auth + METRICS_USERNAME: "prometheus" + METRICS_SECRET: "{{ .STALWART_METRICS_PASSWORD }}" + # Gmail + GMAIL_ADDRESS: "{{ .STALWART_GMAIL_ADDRESS }}" + GMAIL_IMAP_PASSWORD: "{{ .STALWART_GMAIL_IMAP_PASSWORD }}" + GMAIL_SMTP_PASSWORD: "{{ .STALWART_GMAIL_SMTP_PASSWORD }}" + # Migadu + MIGADU_ADDRESS: "{{ .STALWART_MIGADU_ADDRESS }}" + MIGADU_IMAP_PASSWORD: "{{ .STALWART_MIGADU_IMAP_PASSWORD }}" + MIGADU_SMTP_PASSWORD: "{{ .STALWART_MIGADU_SMTP_PASSWORD }}" + # Outlook + OUTLOOK_ADDRESS: "{{ .STALWART_OUTLOOK_ADDRESS }}" + OUTLOOK_SMTP_PASSWORD: "{{ .STALWART_OUTLOOK_SMTP_PASSWORD }}" + OUTLOOK_OAUTH_CLIENT_ID: "{{ .STALWART_OUTLOOK_OAUTH_CLIENT_ID }}" + OUTLOOK_OAUTH_CLIENT_SECRET: "{{ .STALWART_OUTLOOK_OAUTH_CLIENT_SECRET }}" + # Stalwart primary user credentials (used by imapsync and Paperless-ngx) + STALWART_USER: "{{ .STALWART_PRIMARY_USER }}" + STALWART_PASSWORD: "{{ .STALWART_PRIMARY_PASSWORD }}" + dataFrom: + - find: + name: + regexp: ^STALWART.* diff --git a/kubernetes/apps/selfhosted/stalwart/app/helmrelease.yaml b/kubernetes/apps/selfhosted/stalwart/app/helmrelease.yaml new file mode 100644 index 000000000..e983025e3 --- /dev/null +++ b/kubernetes/apps/selfhosted/stalwart/app/helmrelease.yaml @@ -0,0 +1,239 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: stalwart +spec: + interval: 30m + chartRef: + kind: OCIRepository + name: stalwart-mail + install: + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + strategy: rollback + retries: 3 + values: + image: + tag: "v0.15.5" + + # Use ExternalSecret instead of chart-managed secrets + secrets: + create: false + + envFrom: + - secretRef: + name: stalwart-secret + + config: + server: + listener: + smtp: + bind: ["[::]:25"] + protocol: "smtp" + submission: + bind: ["[::]:587"] + protocol: "smtp" + submissions: + bind: ["[::]:465"] + protocol: "smtp" + tls: + implicit: true + imap: + bind: ["[::]:143"] + protocol: "imap" + imaptls: + bind: ["[::]:993"] + protocol: "imap" + tls: + implicit: true + sieve: + bind: ["[::]:4190"] + protocol: "managesieve" + http: + protocol: "http" + bind: ["[::]:80"] + allowed-ip: + "10.0.0.0/8": "" + "172.16.0.0/12": "" + "192.168.0.0/16": "" + + http: + use-x-forwarded: true + + certificate: + default: + default: true + cert: "%{file:/opt/stalwart/etc/certs/tls.crt}%" + private-key: "%{file:/opt/stalwart/etc/certs/tls.key}%" + + storage: + data: "rocksdb" + fts: "rocksdb" + blob: "rocksdb" + lookup: "rocksdb" + directory: "internal" + + store: + rocksdb: + type: rocksdb + path: "/data" + compression: "lz4" + write-buffer-size: 268435456 + + directory: + internal: + type: "internal" + store: "rocksdb" + + authentication: + fallback-admin: + user: "admin" + secret: "%{env:FALLBACK_ADMIN_SECRET}%" + + # Spam filter -- raised threshold for pre-filtered mail + spam-filter: + score: + spam: 8 + discard: 0 + reject: 0 + auto-update: true + header: + is-spam: "X-Spam-Status" + # Trust contacts in address book + dnsbl: + card-is-ham: true + + metrics: + prometheus: + enable: true + auth: + username: "%{env:METRICS_USERNAME}%" + secret: "%{env:METRICS_SECRET}%" + + # Per-sender outbound SMTP relay + queue: + outbound: + hostname: "mail.${SECRET_DOMAIN}" + + # Relay routes + remote: + gmail-relay: + address: "smtp.gmail.com" + port: 587 + protocol: "smtp" + tls: + implicit: false + start-tls: true + auth: + username: "%{env:GMAIL_ADDRESS}%" + secret: "%{env:GMAIL_SMTP_PASSWORD}%" + migadu-relay: + address: "smtp.migadu.com" + port: 587 + protocol: "smtp" + tls: + implicit: false + start-tls: true + auth: + username: "%{env:MIGADU_ADDRESS}%" + secret: "%{env:MIGADU_SMTP_PASSWORD}%" + outlook-relay: + address: "smtp.office365.com" + port: 587 + protocol: "smtp" + tls: + implicit: false + start-tls: true + auth: + username: "%{env:OUTLOOK_ADDRESS}%" + secret: "%{env:OUTLOOK_SMTP_PASSWORD}%" + + tracer: + stdout: + enable: true + type: "stdout" + level: "info" + ansi: false + otel: + enable: false + + # Disable POP3 and HTTPS listeners (unused) + service: + type: LoadBalancer + annotations: + lbipam.cilium.io/ips: ${MAIL_VIP_GATEWAY} + external-dns.alpha.kubernetes.io/hostname: mail.${SECRET_DOMAIN} + ports: + smtp: 25 + submission: 587 + submissions: 465 + imap: 143 + imaptls: 993 + sieve: 4190 + http: 80 + # pop3 (110), pop3s (995), https (443) use chart defaults; + # listeners for these are not configured in config.server.listener above, + # so Stalwart will not actually listen on them even though the Service ports exist. + + ingress: + enabled: true + className: internal + annotations: + external-dns.alpha.kubernetes.io/target: "internal.${SECRET_DOMAIN}" + authentik.home.arpa/internal: "true" + hosts: + - host: &host mail.${SECRET_DOMAIN} + paths: + - path: / + pathType: ImplementationSpecific + tls: + - hosts: + - *host + secretName: ${SECRET_DOMAIN/./-}-tls + + certificate: + secretName: ${SECRET_DOMAIN/./-}-tls + certmanager: + enabled: false + + persistence: + enabled: true + storageClass: ceph-rbd + accessMode: ReadWriteOnce + size: 50Gi + + backup: + enabled: false + + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: 2000m + memory: 4Gi + + livenessProbe: + httpGet: + path: /healthz/live + port: http + httpHeaders: + - name: "X-Forwarded-For" + value: "127.0.0.1" + initialDelaySeconds: 5 + periodSeconds: 10 + + readinessProbe: + httpGet: + path: /healthz/ready + port: http + httpHeaders: + - name: "X-Forwarded-For" + value: "127.0.0.1" + initialDelaySeconds: 30 + periodSeconds: 10 diff --git a/kubernetes/apps/selfhosted/stalwart/app/kustomization.yaml b/kubernetes/apps/selfhosted/stalwart/app/kustomization.yaml new file mode 100644 index 000000000..c665a4d9a --- /dev/null +++ b/kubernetes/apps/selfhosted/stalwart/app/kustomization.yaml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./ocirepository.yaml + - ./helmrelease.yaml + - ./externalsecret.yaml diff --git a/kubernetes/apps/selfhosted/stalwart/app/ocirepository.yaml b/kubernetes/apps/selfhosted/stalwart/app/ocirepository.yaml new file mode 100644 index 000000000..2f90216f3 --- /dev/null +++ b/kubernetes/apps/selfhosted/stalwart/app/ocirepository.yaml @@ -0,0 +1,14 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/source.toolkit.fluxcd.io/ocirepository_v1.json +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: stalwart-mail +spec: + interval: 5m + layerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy + ref: + tag: 0.4.9 + url: oci://codeberg.org/wrenix/helm-charts/stalwart-mail diff --git a/kubernetes/apps/selfhosted/stalwart/ks.yaml b/kubernetes/apps/selfhosted/stalwart/ks.yaml new file mode 100644 index 000000000..cb47b0345 --- /dev/null +++ b/kubernetes/apps/selfhosted/stalwart/ks.yaml @@ -0,0 +1,28 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/kustomize.toolkit.fluxcd.io/kustomization_v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app stalwart + namespace: &namespace selfhosted +spec: + targetNamespace: *namespace + commonMetadata: + labels: + app.kubernetes.io/name: *app + dependsOn: + - name: external-secrets-stores + namespace: external-secrets + path: ./kubernetes/apps/selfhosted/stalwart/app + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + wait: true + interval: 30m + retryInterval: 1m + timeout: 10m + postBuild: + substitute: + APP: *app diff --git a/kubernetes/flux/components/common/substitutions/cluster-settings.yaml b/kubernetes/flux/components/common/substitutions/cluster-settings.yaml index f2c26479d..fc9c4d338 100644 --- a/kubernetes/flux/components/common/substitutions/cluster-settings.yaml +++ b/kubernetes/flux/components/common/substitutions/cluster-settings.yaml @@ -21,3 +21,4 @@ data: SMTP_VIP_GATEWAY: "10.100.0.27" NUT_VIP_GATEWAY: "10.100.0.28" WAZUH_VIP_GATEWAY: "10.100.0.29" + MAIL_VIP_GATEWAY: "10.100.0.30"