diff --git a/apps/irc/irc.yaml b/apps/irc/irc.yaml index dab1b92..19d0d3e 100644 --- a/apps/irc/irc.yaml +++ b/apps/irc/irc.yaml @@ -1,184 +1,554 @@ -# UnrealIRCd + Anope IRC Services -# PLACEHOLDER - UnrealIRCd needs config files mounted before running -# ArgoCD managed - BlueJay Lab ---- -apiVersion: v1 -kind: Namespace -metadata: - name: irc - labels: - app.kubernetes.io/part-of: bluejay-infra ---- -# UnrealIRCd PVC -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: unrealircd-data - namespace: irc -spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 1Gi ---- -# Anope PVC -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: anope-data - namespace: irc -spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 1Gi ---- -# UnrealIRCd Deployment -# NOTE: This is a placeholder. UnrealIRCd requires configuration files -# (unrealircd.conf, TLS certs, etc.) to be present in /data before starting. -# Mount config via ConfigMap/Secret or init container before enabling. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: unrealircd - namespace: irc - labels: - app: unrealircd -spec: - replicas: 1 - selector: - matchLabels: - app: unrealircd - template: - metadata: - labels: - app: unrealircd - spec: - containers: - - name: unrealircd - image: ghcr.io/unrealircd/unrealircd:latest - ports: - - containerPort: 6667 - name: irc-plain - - containerPort: 6697 - name: irc-tls - - containerPort: 8067 - name: services-link - volumeMounts: - - name: unrealircd-data - mountPath: /data - resources: - requests: - memory: 64Mi - cpu: 50m - limits: - memory: 256Mi - cpu: 250m - volumes: - - name: unrealircd-data - persistentVolumeClaim: - claimName: unrealircd-data ---- -# Anope IRC Services Deployment -# NOTE: Placeholder. Anope requires services.conf with link block -# matching UnrealIRCd's link configuration. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: anope - namespace: irc - labels: - app: anope -spec: - replicas: 1 - selector: - matchLabels: - app: anope - template: - metadata: - labels: - app: anope - spec: - containers: - - name: anope - image: anope/anope:latest - volumeMounts: - - name: anope-data - mountPath: /data - resources: - requests: - memory: 64Mi - cpu: 25m - limits: - memory: 128Mi - cpu: 100m - volumes: - - name: anope-data - persistentVolumeClaim: - claimName: anope-data ---- -# UnrealIRCd Service (ClusterIP for internal + Traefik TCP routing) -apiVersion: v1 -kind: Service -metadata: - name: unrealircd - namespace: irc -spec: - selector: - app: unrealircd - ports: - - port: 6667 - targetPort: 6667 - name: irc-plain - - port: 6697 - targetPort: 6697 - name: irc-tls - - port: 8067 - targetPort: 8067 - name: services-link ---- -# Anope Service -apiVersion: v1 -kind: Service -metadata: - name: anope - namespace: irc -spec: - selector: - app: anope - ports: - - port: 8067 - targetPort: 8067 - name: services-link ---- -# Traefik IngressRouteTCP - IRC plain (6667) -apiVersion: traefik.io/v1alpha1 -kind: IngressRouteTCP -metadata: - name: irc-plain - namespace: irc -spec: - entryPoints: - - irc - routes: - - match: HostSNI(`*`) - services: - - name: unrealircd - port: 6667 ---- -# Traefik IngressRouteTCP - IRC TLS passthrough (6697) -apiVersion: traefik.io/v1alpha1 -kind: IngressRouteTCP -metadata: - name: irc-tls - namespace: irc -spec: - entryPoints: - - ircs - routes: - - match: HostSNI(`*`) - services: - - name: unrealircd - port: 6697 - tls: - passthrough: true +# UnrealIRCd + Anope IRC Services +# ArgoCD managed - BlueJay Lab +--- +apiVersion: v1 +kind: Namespace +metadata: + name: irc + labels: + app.kubernetes.io/part-of: bluejay-infra +--- +# TLS Certificate for IRC +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: irc-tls + namespace: irc +spec: + secretName: irc-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - irc.iamworkin.lan +--- +# UnrealIRCd configuration +apiVersion: v1 +kind: Secret +metadata: + name: unrealircd-config + namespace: irc +type: Opaque +stringData: + unrealircd.conf: | + /* BlueJay Lab IRC - UnrealIRCd 6.x config */ + /* Managed by ArgoCD */ + + include "modules.default.conf"; + include "help/help.conf"; + include "operclass.default.conf"; + include "snomasks.default.conf"; + + me { + name "irc.iamworkin.lan"; + info "BlueJay Lab IRC Server"; + sid 001; + } + + admin { + "BlueJay Lab IRC"; + "admin@iamwork.in"; + } + + class clients { + pingfreq 90; + maxclients 500; + sendq 200k; + recvq 8000; + } + + class opers { + pingfreq 90; + maxclients 50; + sendq 1M; + recvq 8000; + } + + class servers { + pingfreq 60; + connfreq 15; + maxclients 10; + sendq 20M; + } + + allow { + mask *; + class clients; + maxperip 5; + } + + listen { + ip *; + port 6667; + } + + listen { + ip *; + port 6697; + options { tls; } + tls-options { + certificate "/etc/ssl/irc/tls.crt"; + key "/etc/ssl/irc/tls.key"; + } + } + + listen { + ip *; + port 8067; + } + + oper bluejay { + mask *; + password "BlueJay-IRC-Oper-2026"; + operclass netadmin-with-override; + class opers; + } + + drpass { + restart "BlueJay-IRC-Oper-2026"; + die "BlueJay-IRC-Oper-2026"; + } + + link services.iamworkin.lan { + incoming { + mask *; + } + password "BlueJay-Services-Link-2026"; + class servers; + } + + ulines { + services.iamworkin.lan; + } + + log { + source { + all; + \!debug; + } + destination { + channel "#ops"; + } + } + + set { + network-name "BlueJayIRC"; + default-server "irc.iamworkin.lan"; + services-server "services.iamworkin.lan"; + stats-server "stats.iamworkin.lan"; + help-channel "#general"; + cloak-keys { + "bluejay-cloak-key-1-aHR0cHM6Ly9pcmM"; + "bluejay-cloak-key-2-aWFtd29ya2luLmxhbg"; + "bluejay-cloak-key-3-Ymx1ZWpheS1pcmM"; + } + kline-address "admin@iamwork.in"; + maxchannelsperuser 25; + anti-flood { + everyone { + connect-flood 3:60; + } + } + options { + hide-ulines; + show-connect-info; + } + + /* TLS config */ + tls { + certificate "/etc/ssl/irc/tls.crt"; + key "/etc/ssl/irc/tls.key"; + } + } +--- +# Anope configuration +apiVersion: v1 +kind: Secret +metadata: + name: anope-config + namespace: irc +type: Opaque +stringData: + services.conf: | + define { + name = "services.host" + value = "services.iamworkin.lan" + } + + uplink { + host = "unrealircd.irc.svc.cluster.local" + port = 8067 + password = "BlueJay-Services-Link-2026" + } + + serverinfo { + name = "services.iamworkin.lan" + description = "BlueJay IRC Services" + pid = "/data/services.pid" + motd = "/data/services.motd" + } + + module { + name = "unreal4" + } + + networkinfo { + networkname = "BlueJayIRC" + nicklen = 31 + userlen = 10 + hostlen = 64 + chanlen = 32 + mail_from = "noreply@iamwork.in" + } + + options { + casemap = "ascii" + seed = 42 + strictpasswords + } + + module { name = "nickserv" } + module { name = "chanserv" } + module { name = "operserv" } + module { name = "botserv" } + module { name = "hostserv" } + module { name = "memoserv" } + module { name = "global" } + + module { name = "db_flatfile" } + module { name = "enc_sha256" } + module { name = "ns_access" } + module { name = "ns_ajoin" } + module { name = "ns_cert" } + module { name = "ns_drop" } + module { name = "ns_group" } + module { name = "ns_identify" } + module { name = "ns_info" } + module { name = "ns_list" } + module { name = "ns_logout" } + module { name = "ns_recover" } + module { name = "ns_register" } + module { name = "ns_set" } + module { name = "ns_suspend" } + module { name = "ns_update" } + module { name = "cs_access" } + module { name = "cs_akick" } + module { name = "cs_ban" } + module { name = "cs_clone" } + module { name = "cs_drop" } + module { name = "cs_enforce" } + module { name = "cs_entrymsg" } + module { name = "cs_flags" } + module { name = "cs_info" } + module { name = "cs_invite" } + module { name = "cs_kick" } + module { name = "cs_list" } + module { name = "cs_log" } + module { name = "cs_mode" } + module { name = "cs_register" } + module { name = "cs_seen" } + module { name = "cs_set" } + module { name = "cs_suspend" } + module { name = "cs_topic" } + module { name = "cs_unban" } + module { name = "os_akill" } + module { name = "os_chankill" } + module { name = "os_defcon" } + module { name = "os_forbid" } + module { name = "os_ignore" } + module { name = "os_info" } + module { name = "os_jupe" } + module { name = "os_kick" } + module { name = "os_kill" } + module { name = "os_list" } + module { name = "os_login" } + module { name = "os_logsearch" } + module { name = "os_mode" } + module { name = "os_modinfo" } + module { name = "os_module" } + module { name = "os_noop" } + module { name = "os_oper" } + module { name = "os_reload" } + module { name = "os_session" } + module { name = "os_set" } + module { name = "os_shutdown" } + module { name = "os_stats" } + module { name = "os_svsnick" } + module { name = "os_sxline" } + module { name = "os_update" } + module { name = "bs_assign" } + module { name = "bs_badwords" } + module { name = "bs_bot" } + module { name = "bs_info" } + module { name = "bs_kick" } + module { name = "bs_set" } + module { name = "hs_del" } + module { name = "hs_group" } + module { name = "hs_list" } + module { name = "hs_off" } + module { name = "hs_on" } + module { name = "hs_request" } + module { name = "hs_set" } + module { name = "ms_cancel" } + module { name = "ms_check" } + module { name = "ms_del" } + module { name = "ms_ignore" } + module { name = "ms_info" } + module { name = "ms_list" } + module { name = "ms_read" } + module { name = "ms_rsend" } + module { name = "ms_send" } + module { name = "ms_set" } + module { name = "gl_global" } + module { name = "m_dns" } + module { name = "m_helpchan" } + module { name = "m_httpd" } + module { name = "m_ldap" } + module { name = "m_xmlrpc" } + module { name = "m_proxyscan" } + + nickserv { + nick = "NickServ" + defaults = "kill_quick ns_secure ns_private hide_email" + registration = "none" + expire = 90d + } + + chanserv { + nick = "ChanServ" + defaults = "keeptopic peace cs_secure" + expire = 14d + } + + operserv { + nick = "OperServ" + } + + botserv { + nick = "BotServ" + defaults = "dontkickops fantasy greet" + } + + hostserv { + nick = "HostServ" + } + + memoserv { + nick = "MemoServ" + maxmemos = 20 + } + + global { + nick = "Global" + } + + service { + nick = "bluejay" + } + + oper { + name = "bluejay" + type = "Services Root" + } + + db_flatfile { + database = "/data/anope.db" + fork = yes + } + + log { + target = "/data/services.log" + admin = "*" + override = "chanserv/* nickserv/* operserv/*" + commands = "chanserv/* nickserv/* operserv/*" + servers = "*" + channels = "*" + users = "connect disconnect" + } +--- +# UnrealIRCd PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: unrealircd-data + namespace: irc +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 1Gi +--- +# Anope PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: anope-data + namespace: irc +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 1Gi +--- +# UnrealIRCd Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: unrealircd + namespace: irc + labels: + app: unrealircd +spec: + replicas: 1 + selector: + matchLabels: + app: unrealircd + template: + metadata: + labels: + app: unrealircd + spec: + containers: + - name: unrealircd + image: ircd/unrealircd:latest + ports: + - containerPort: 6667 + name: irc-plain + - containerPort: 6697 + name: irc-tls + - containerPort: 8067 + name: services-link + volumeMounts: + - name: unrealircd-config + mountPath: /ircd/unrealircd.conf + subPath: unrealircd.conf + - name: unrealircd-data + mountPath: /data + - name: irc-tls + mountPath: /etc/ssl/irc + readOnly: true + resources: + requests: + memory: 64Mi + cpu: 50m + limits: + memory: 256Mi + cpu: 250m + volumes: + - name: unrealircd-config + secret: + secretName: unrealircd-config + - name: unrealircd-data + persistentVolumeClaim: + claimName: unrealircd-data + - name: irc-tls + secret: + secretName: irc-tls +--- +# Anope IRC Services Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: anope + namespace: irc + labels: + app: anope +spec: + replicas: 1 + selector: + matchLabels: + app: anope + template: + metadata: + labels: + app: anope + spec: + containers: + - name: anope + image: anope/anope:latest + volumeMounts: + - name: anope-config + mountPath: /data/conf/services.conf + subPath: services.conf + - name: anope-data + mountPath: /data + resources: + requests: + memory: 64Mi + cpu: 25m + limits: + memory: 128Mi + cpu: 100m + volumes: + - name: anope-config + secret: + secretName: anope-config + - name: anope-data + persistentVolumeClaim: + claimName: anope-data +--- +# UnrealIRCd Service +apiVersion: v1 +kind: Service +metadata: + name: unrealircd + namespace: irc +spec: + selector: + app: unrealircd + ports: + - port: 6667 + targetPort: 6667 + name: irc-plain + - port: 6697 + targetPort: 6697 + name: irc-tls + - port: 8067 + targetPort: 8067 + name: services-link +--- +# Anope Service +apiVersion: v1 +kind: Service +metadata: + name: anope + namespace: irc +spec: + selector: + app: anope + ports: + - port: 8067 + targetPort: 8067 + name: services-link +--- +# Traefik IngressRouteTCP - IRC plain (6667) +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: irc-plain + namespace: irc +spec: + entryPoints: + - irc + routes: + - match: HostSNI(`*`) + services: + - name: unrealircd + port: 6667 +--- +# Traefik IngressRouteTCP - IRC TLS passthrough (6697) +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: irc-tls + namespace: irc +spec: + entryPoints: + - irctls + routes: + - match: HostSNI(`*`) + services: + - name: unrealircd + port: 6697 + tls: + passthrough: true diff --git a/apps/mail/mail.yaml b/apps/mail/mail.yaml index e0305a7..7fde47c 100644 --- a/apps/mail/mail.yaml +++ b/apps/mail/mail.yaml @@ -1,203 +1,222 @@ -# docker-mailserver - Postfix + Dovecot + rspamd -# ArgoCD managed - BlueJay Lab ---- -apiVersion: v1 -kind: Namespace -metadata: - name: mail - labels: - app.kubernetes.io/part-of: bluejay-infra ---- -# Mail data PVC -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mail-data - namespace: mail -spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Gi ---- -# Mail state PVC -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mail-state - namespace: mail -spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 1Gi ---- -# docker-mailserver Deployment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mailserver - namespace: mail - labels: - app: mailserver -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: mailserver - template: - metadata: - labels: - app: mailserver - spec: - hostname: mail - containers: - - name: mailserver - image: docker.io/mailserver/docker-mailserver:latest - ports: - - containerPort: 25 - name: smtp - - containerPort: 465 - name: smtps - - containerPort: 587 - name: submission - - containerPort: 143 - name: imap - - containerPort: 993 - name: imaps - env: - - name: ENABLE_SPAMASSASSIN - value: "1" - - name: ENABLE_CLAMAV - value: "0" - - name: ENABLE_RSPAMD - value: "1" - - name: TZ - value: America/Chicago - - name: POSTMASTER_ADDRESS - value: postmaster@iamwork.in - - name: OVERRIDE_HOSTNAME - value: mail.iamwork.in - - name: ENABLE_FAIL2BAN - value: "0" - - name: ENABLE_POSTGREY - value: "0" - - name: ONE_DIR - value: "1" - - name: PERMIT_DOCKER - value: network - - name: SSL_TYPE - value: manual - - name: SSL_CERT_PATH - value: /etc/ssl/mail/tls.crt - - name: SSL_KEY_PATH - value: /etc/ssl/mail/tls.key - volumeMounts: - - name: mail-data - mountPath: /var/mail - - name: mail-state - mountPath: /var/mail-state - - name: mail-tls - mountPath: /etc/ssl/mail - readOnly: true - resources: - requests: - memory: 512Mi - cpu: 200m - limits: - memory: 2Gi - cpu: "1" - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_PTRACE - volumes: - - name: mail-data - persistentVolumeClaim: - claimName: mail-data - - name: mail-state - persistentVolumeClaim: - claimName: mail-state - - name: mail-tls - secret: - secretName: mail-tls ---- -# SMTP LoadBalancer Service (external) -apiVersion: v1 -kind: Service -metadata: - name: mail-smtp - namespace: mail - annotations: - metallb.universe.tf/loadBalancerIPs: 10.0.56.202 -spec: - type: LoadBalancer - selector: - app: mailserver - ports: - - port: 25 - targetPort: 25 - name: smtp - protocol: TCP - - port: 465 - targetPort: 465 - name: smtps - protocol: TCP - - port: 587 - targetPort: 587 - name: submission - protocol: TCP ---- -# IMAP ClusterIP Service (internal) -apiVersion: v1 -kind: Service -metadata: - name: mail-imap - namespace: mail -spec: - selector: - app: mailserver - ports: - - port: 143 - targetPort: 143 - name: imap - - port: 993 - targetPort: 993 - name: imaps ---- -# TLS Certificate via cert-manager -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: mail-tls - namespace: mail -spec: - secretName: mail-tls - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - dnsNames: - - mail.iamworkin.lan ---- -# Traefik IngressRoute - Webmail placeholder -# Snappymail will need a separate deployment; this routes to the -# mail server's HTTP port if available, or to a future webmail deployment -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: mail-webmail - namespace: mail -spec: - entryPoints: - - websecure - routes: - - match: Host(`mail.iamworkin.lan`) - kind: Rule - services: - - name: mail-imap - port: 993 - tls: - secretName: mail-tls +# docker-mailserver - Postfix + Dovecot + rspamd +# ArgoCD managed - BlueJay Lab +--- +apiVersion: v1 +kind: Namespace +metadata: + name: mail + labels: + app.kubernetes.io/part-of: bluejay-infra +--- +# Mail accounts Secret (postfix-accounts.cf format: user@domain|{SHA512-CRYPT}hash) +apiVersion: v1 +kind: Secret +metadata: + name: mail-accounts + namespace: mail +type: Opaque +stringData: + postfix-accounts.cf: | + admin@iamwork.in|{SHA512-CRYPT}$6$1355214084ba403a$LPA.qkZLpv9RqMu8OenCrgYgyHbMwMIAYOuLrbNX/eeiaOj.8rtj9IlMeLDxSc6FdWK9N/PcNmBzV5fJL7IRn/ + noreply@iamwork.in|{SHA512-CRYPT}$6$1355214084ba403a$LPA.qkZLpv9RqMu8OenCrgYgyHbMwMIAYOuLrbNX/eeiaOj.8rtj9IlMeLDxSc6FdWK9N/PcNmBzV5fJL7IRn/ +--- +# Mail data PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mail-data + namespace: mail +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 5Gi +--- +# Mail state PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mail-state + namespace: mail +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 1Gi +--- +# docker-mailserver Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mailserver + namespace: mail + labels: + app: mailserver +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: mailserver + template: + metadata: + labels: + app: mailserver + spec: + hostname: mail + containers: + - name: mailserver + image: docker.io/mailserver/docker-mailserver:latest + ports: + - containerPort: 25 + name: smtp + - containerPort: 465 + name: smtps + - containerPort: 587 + name: submission + - containerPort: 143 + name: imap + - containerPort: 993 + name: imaps + env: + - name: ENABLE_SPAMASSASSIN + value: "1" + - name: ENABLE_CLAMAV + value: "0" + - name: ENABLE_RSPAMD + value: "1" + - name: TZ + value: America/Chicago + - name: POSTMASTER_ADDRESS + value: postmaster@iamwork.in + - name: OVERRIDE_HOSTNAME + value: mail.iamwork.in + - name: ENABLE_FAIL2BAN + value: "0" + - name: ENABLE_POSTGREY + value: "0" + - name: ONE_DIR + value: "1" + - name: PERMIT_DOCKER + value: network + - name: SSL_TYPE + value: manual + - name: SSL_CERT_PATH + value: /etc/ssl/mail/tls.crt + - name: SSL_KEY_PATH + value: /etc/ssl/mail/tls.key + - name: ACCOUNT_PROVISIONER + value: FILE + volumeMounts: + - name: mail-data + mountPath: /var/mail + - name: mail-state + mountPath: /var/mail-state + - name: mail-tls + mountPath: /etc/ssl/mail + readOnly: true + - name: mail-accounts + mountPath: /tmp/docker-mailserver/postfix-accounts.cf + subPath: postfix-accounts.cf + readOnly: true + resources: + requests: + memory: 512Mi + cpu: 200m + limits: + memory: 2Gi + cpu: "1" + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_PTRACE + volumes: + - name: mail-data + persistentVolumeClaim: + claimName: mail-data + - name: mail-state + persistentVolumeClaim: + claimName: mail-state + - name: mail-tls + secret: + secretName: mail-tls + - name: mail-accounts + secret: + secretName: mail-accounts +--- +# SMTP LoadBalancer Service (external) +apiVersion: v1 +kind: Service +metadata: + name: mail-smtp + namespace: mail + annotations: + metallb.universe.tf/loadBalancerIPs: 10.0.56.202 +spec: + type: LoadBalancer + selector: + app: mailserver + ports: + - port: 25 + targetPort: 25 + name: smtp + protocol: TCP + - port: 465 + targetPort: 465 + name: smtps + protocol: TCP + - port: 587 + targetPort: 587 + name: submission + protocol: TCP +--- +# IMAP ClusterIP Service (internal) +apiVersion: v1 +kind: Service +metadata: + name: mail-imap + namespace: mail +spec: + selector: + app: mailserver + ports: + - port: 143 + targetPort: 143 + name: imap + - port: 993 + targetPort: 993 + name: imaps +--- +# TLS Certificate via cert-manager +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: mail-tls + namespace: mail +spec: + secretName: mail-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - mail.iamworkin.lan +--- +# Traefik IngressRoute - Webmail placeholder +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: mail-webmail + namespace: mail +spec: + entryPoints: + - websecure + routes: + - match: Host(`mail.iamworkin.lan`) + kind: Rule + services: + - name: mail-imap + port: 993 + tls: + secretName: mail-tls diff --git a/apps/matrix/matrix.yaml b/apps/matrix/matrix.yaml index 0d8e195..1eb7a04 100644 --- a/apps/matrix/matrix.yaml +++ b/apps/matrix/matrix.yaml @@ -1,354 +1,403 @@ -# Matrix Synapse + Element Web -# PostgreSQL 16 + Synapse homeserver + Element Web client -# ArgoCD managed - BlueJay Lab ---- -apiVersion: v1 -kind: Namespace -metadata: - name: matrix - labels: - app.kubernetes.io/part-of: bluejay-infra ---- -apiVersion: v1 -kind: Secret -metadata: - name: matrix-db-secret - namespace: matrix -type: Opaque -stringData: - POSTGRES_USER: synapse - POSTGRES_PASSWORD: BlueJay-Matrix-DB-2026 - POSTGRES_DB: synapse - POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" ---- -# PostgreSQL 16 StatefulSet -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: matrix-postgres - namespace: matrix - labels: - app: matrix-postgres -spec: - serviceName: matrix-postgres - replicas: 1 - selector: - matchLabels: - app: matrix-postgres - template: - metadata: - labels: - app: matrix-postgres - spec: - containers: - - name: postgres - image: postgres:16-alpine - ports: - - containerPort: 5432 - name: postgres - envFrom: - - secretRef: - name: matrix-db-secret - volumeMounts: - - name: matrix-postgres-data - mountPath: /var/lib/postgresql/data - subPath: pgdata - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 1Gi - cpu: 500m - livenessProbe: - exec: - command: - - pg_isready - - -U - - synapse - initialDelaySeconds: 30 - periodSeconds: 10 - readinessProbe: - exec: - command: - - pg_isready - - -U - - synapse - initialDelaySeconds: 5 - periodSeconds: 5 - volumeClaimTemplates: - - metadata: - name: matrix-postgres-data - spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 5Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: matrix-postgres - namespace: matrix -spec: - selector: - app: matrix-postgres - ports: - - port: 5432 - targetPort: 5432 - name: postgres - clusterIP: None ---- -# Synapse Data PVC -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: synapse-data - namespace: matrix -spec: - accessModes: [ReadWriteOnce] - resources: - requests: - storage: 2Gi ---- -# Synapse Homeserver Deployment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: synapse - namespace: matrix - labels: - app: synapse -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: synapse - template: - metadata: - labels: - app: synapse - spec: - containers: - - name: synapse - image: matrixdotorg/synapse:latest - ports: - - containerPort: 8008 - name: http - env: - - name: SYNAPSE_SERVER_NAME - value: iamworkin.lan - - name: SYNAPSE_REPORT_STATS - value: "no" - - name: SYNAPSE_CONFIG_DIR - value: /data - - name: SYNAPSE_DATA_DIR - value: /data - - name: POSTGRES_HOST - value: matrix-postgres - - name: POSTGRES_PORT - value: "5432" - - name: POSTGRES_DB - valueFrom: - secretKeyRef: - name: matrix-db-secret - key: POSTGRES_DB - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: matrix-db-secret - key: POSTGRES_USER - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: matrix-db-secret - key: POSTGRES_PASSWORD - volumeMounts: - - name: synapse-data - mountPath: /data - resources: - requests: - memory: 512Mi - cpu: 200m - limits: - memory: 2Gi - cpu: "1" - livenessProbe: - httpGet: - path: /health - port: 8008 - initialDelaySeconds: 60 - periodSeconds: 10 - readinessProbe: - httpGet: - path: /health - port: 8008 - initialDelaySeconds: 30 - periodSeconds: 5 - volumes: - - name: synapse-data - persistentVolumeClaim: - claimName: synapse-data ---- -apiVersion: v1 -kind: Service -metadata: - name: synapse - namespace: matrix -spec: - selector: - app: synapse - ports: - - port: 8008 - targetPort: 8008 - name: http ---- -# Element Web ConfigMap -apiVersion: v1 -kind: ConfigMap -metadata: - name: element-web-config - namespace: matrix -data: - config.json: | - { - "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.iamworkin.lan", - "server_name": "iamworkin.lan" - } - }, - "brand": "BlueJay Chat", - "disable_guests": true, - "disable_3pid_login": true - } ---- -# Element Web Deployment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: element-web - namespace: matrix - labels: - app: element-web -spec: - replicas: 1 - selector: - matchLabels: - app: element-web - template: - metadata: - labels: - app: element-web - spec: - containers: - - name: element-web - image: vectorim/element-web:latest - ports: - - containerPort: 80 - name: http - volumeMounts: - - name: element-config - mountPath: /app/config.json - subPath: config.json - resources: - requests: - memory: 32Mi - cpu: 10m - limits: - memory: 128Mi - cpu: 100m - livenessProbe: - httpGet: - path: / - port: 80 - initialDelaySeconds: 10 - periodSeconds: 10 - readinessProbe: - httpGet: - path: / - port: 80 - initialDelaySeconds: 5 - periodSeconds: 5 - volumes: - - name: element-config - configMap: - name: element-web-config ---- -apiVersion: v1 -kind: Service -metadata: - name: element-web - namespace: matrix -spec: - selector: - app: element-web - ports: - - port: 80 - targetPort: 80 - name: http ---- -# TLS Certificates via cert-manager -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: matrix-tls - namespace: matrix -spec: - secretName: matrix-tls - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - dnsNames: - - matrix.iamworkin.lan ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: element-tls - namespace: matrix -spec: - secretName: element-tls - issuerRef: - name: step-ca-acme - kind: ClusterIssuer - dnsNames: - - element.iamworkin.lan ---- -# Traefik IngressRoute - Synapse -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: synapse - namespace: matrix -spec: - entryPoints: - - websecure - routes: - - match: Host(`matrix.iamworkin.lan`) - kind: Rule - services: - - name: synapse - port: 8008 - tls: - secretName: matrix-tls ---- -# Traefik IngressRoute - Element Web -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: element-web - namespace: matrix -spec: - entryPoints: - - websecure - routes: - - match: Host(`element.iamworkin.lan`) - kind: Rule - services: - - name: element-web - port: 80 - tls: - secretName: element-tls +# Matrix Synapse + Element Web +# PostgreSQL 16 + Synapse homeserver + Element Web client +# ArgoCD managed - BlueJay Lab +--- +apiVersion: v1 +kind: Namespace +metadata: + name: matrix + labels: + app.kubernetes.io/part-of: bluejay-infra +--- +apiVersion: v1 +kind: Secret +metadata: + name: matrix-db-secret + namespace: matrix +type: Opaque +stringData: + POSTGRES_USER: synapse + POSTGRES_PASSWORD: BlueJay-Matrix-DB-2026 + POSTGRES_DB: synapse + POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" +--- +# Synapse homeserver.yaml ConfigMap +apiVersion: v1 +kind: ConfigMap +metadata: + name: synapse-config + namespace: matrix +data: + homeserver.yaml: | + server_name: "iamworkin.lan" + pid_file: /data/homeserver.pid + public_baseurl: "https://matrix.iamworkin.lan/" + listeners: + - port: 8008 + tls: false + type: http + x_forwarded: true + bind_addresses: ["0.0.0.0"] + resources: + - names: [client, federation] + compress: false + database: + name: psycopg2 + args: + user: synapse + password: BlueJay-Matrix-DB-2026 + database: synapse + host: matrix-postgres + port: 5432 + cp_min: 5 + cp_max: 10 + log_config: "/data/log.config" + media_store_path: /data/media_store + registration_shared_secret: "a208f2e4b260f6b7d6ff4566df49c56c8b73fa20b911ce4e617b791ee7868adc" + report_stats: false + macaroon_secret_key: "9964f398e8b48a91469ad419d293c06db4562f49df8cc6e129fb3a801fd9052d" + form_secret: "7b0a9dbaf9ee94450e0b3271c408dfc4d313a55843ce4eec2ac1bb0315ffeb76" + signing_key_path: "/data/signing.key" + trusted_key_servers: + - server_name: "matrix.org" + enable_registration: false + suppress_key_server_warning: true + log.config: | + version: 1 + formatters: + precise: + format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s" + handlers: + console: + class: logging.StreamHandler + formatter: precise + loggers: + synapse.storage.SQL: + level: WARNING + root: + level: WARNING + handlers: [console] + disable_existing_loggers: false +--- +# PostgreSQL 16 StatefulSet +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: matrix-postgres + namespace: matrix + labels: + app: matrix-postgres +spec: + serviceName: matrix-postgres + replicas: 1 + selector: + matchLabels: + app: matrix-postgres + template: + metadata: + labels: + app: matrix-postgres + spec: + containers: + - name: postgres + image: postgres:16-alpine + ports: + - containerPort: 5432 + name: postgres + envFrom: + - secretRef: + name: matrix-db-secret + volumeMounts: + - name: matrix-postgres-data + mountPath: /var/lib/postgresql/data + subPath: pgdata + resources: + requests: + memory: 256Mi + cpu: 100m + limits: + memory: 1Gi + cpu: 500m + livenessProbe: + exec: + command: ["pg_isready", "-U", "synapse"] + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + exec: + command: ["pg_isready", "-U", "synapse"] + initialDelaySeconds: 5 + periodSeconds: 5 + volumeClaimTemplates: + - metadata: + name: matrix-postgres-data + spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: matrix-postgres + namespace: matrix +spec: + selector: + app: matrix-postgres + ports: + - port: 5432 + targetPort: 5432 + name: postgres + clusterIP: None +--- +# Synapse Data PVC +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: synapse-data + namespace: matrix +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 2Gi +--- +# Synapse init job: generate signing key if missing +apiVersion: apps/v1 +kind: Deployment +metadata: + name: synapse + namespace: matrix + labels: + app: synapse +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: synapse + template: + metadata: + labels: + app: synapse + spec: + initContainers: + - name: generate-signing-key + image: matrixdotorg/synapse:latest + command: ["sh", "-c"] + args: + - | + if [ \! -f /data/signing.key ]; then + python -m synapse.app.homeserver --generate-keys --config-path /config/homeserver.yaml + fi + volumeMounts: + - name: synapse-data + mountPath: /data + - name: synapse-config + mountPath: /config + containers: + - name: synapse + image: matrixdotorg/synapse:latest + ports: + - containerPort: 8008 + name: http + env: + - name: SYNAPSE_CONFIG_DIR + value: /config + - name: SYNAPSE_CONFIG_PATH + value: /config/homeserver.yaml + volumeMounts: + - name: synapse-data + mountPath: /data + - name: synapse-config + mountPath: /config + resources: + requests: + memory: 512Mi + cpu: 200m + limits: + memory: 2Gi + cpu: "1" + livenessProbe: + httpGet: + path: /health + port: 8008 + initialDelaySeconds: 60 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /health + port: 8008 + initialDelaySeconds: 30 + periodSeconds: 5 + volumes: + - name: synapse-data + persistentVolumeClaim: + claimName: synapse-data + - name: synapse-config + configMap: + name: synapse-config +--- +apiVersion: v1 +kind: Service +metadata: + name: synapse + namespace: matrix +spec: + selector: + app: synapse + ports: + - port: 8008 + targetPort: 8008 + name: http +--- +# Element Web ConfigMap +apiVersion: v1 +kind: ConfigMap +metadata: + name: element-web-config + namespace: matrix +data: + config.json: | + { + "default_server_config": { + "m.homeserver": { + "base_url": "https://matrix.iamworkin.lan", + "server_name": "iamworkin.lan" + } + }, + "brand": "BlueJay Chat", + "disable_guests": true, + "disable_3pid_login": true + } +--- +# Element Web Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: element-web + namespace: matrix + labels: + app: element-web +spec: + replicas: 1 + selector: + matchLabels: + app: element-web + template: + metadata: + labels: + app: element-web + spec: + enableServiceLinks: false + containers: + - name: element-web + image: vectorim/element-web:latest + ports: + - containerPort: 80 + name: http + volumeMounts: + - name: element-config + mountPath: /app/config.json + subPath: config.json + resources: + requests: + memory: 32Mi + cpu: 10m + limits: + memory: 128Mi + cpu: 100m + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 + volumes: + - name: element-config + configMap: + name: element-web-config +--- +apiVersion: v1 +kind: Service +metadata: + name: element-web + namespace: matrix +spec: + selector: + app: element-web + ports: + - port: 80 + targetPort: 80 + name: http +--- +# TLS Certificates via cert-manager +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: matrix-tls + namespace: matrix +spec: + secretName: matrix-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - matrix.iamworkin.lan +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: element-tls + namespace: matrix +spec: + secretName: element-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - element.iamworkin.lan +--- +# Traefik IngressRoute - Synapse +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: synapse + namespace: matrix +spec: + entryPoints: + - websecure + routes: + - match: Host(`matrix.iamworkin.lan`) + kind: Rule + services: + - name: synapse + port: 8008 + tls: + secretName: matrix-tls +--- +# Traefik IngressRoute - Element Web +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: element-web + namespace: matrix +spec: + entryPoints: + - websecure + routes: + - match: Host(`element.iamworkin.lan`) + kind: Rule + services: + - name: element-web + port: 80 + tls: + secretName: element-tls