Add new infra architecture

This commit is contained in:
Urtzi Alfaro
2026-01-19 11:55:17 +01:00
parent 21d35ea92b
commit 35f164f0cd
311 changed files with 13241 additions and 3700 deletions

View File

@@ -0,0 +1,289 @@
# Mailu Email Infrastructure for Bakery-IA
This directory contains the Kubernetes deployment configuration for Mailu, a self-hosted email solution that integrates with external SMTP relays for optimal deliverability.
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster (bakery-ia) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ notification- │ │ mail-service │ │ frontend │ │
│ │ service │─────▶│ (new/optional) │ │ │ │
│ │ │ │ Queue & Routing │ │ │ │
│ └────────┬─────────┘ └────────┬─────────┘ └──────────────────┘ │
│ │ │ │
│ │ SMTP (port 587) │ SMTP (port 587) │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ MAILU STACK │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ front │ │ admin │ │ smtp │ │ imap │ │ │
│ │ │ (nginx) │ │ (webmail) │ │ (postfix) │ │ (dovecot) │ │ │
│ │ │ :80/:443 │ │ :8080 │ │ :25/:587 │ │ :993/:143 │ │ │
│ │ └─────────────┘ └─────────────┘ └──────┬──────┘ └─────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ Relay │ │
│ │ │ antispam │ │ antivirus │ │ │ │
│ │ │ (rspamd) │ │ (clamav) │ │ │ │
│ │ └─────────────┘ └─────────────┘ │ │ │
│ │ │ │ │
│ │ ┌─────────────────────────────────┐ │ │ │
│ │ │ mailu-db (redis) │ │ │ │
│ │ └─────────────────────────────────┘ │ │ │
│ └───────────────────────────────────────────┼──────────────────────────┘ │
│ │ │
└──────────────────────────────────────────────┼───────────────────────────────┘
┌──────────────────────────────────────┐
│ EXTERNAL SMTP RELAY │
│ (SendGrid / Mailgun / AWS SES) │
│ │
│ • Handles IP reputation │
│ • Manages deliverability │
│ • Provides bounce/complaint hooks │
└──────────────────────────────────────┘
┌──────────────────────────────────────┐
│ INTERNET / RECIPIENTS │
└──────────────────────────────────────┘
```
## Components
### Core Services
- **mailu-front**: Nginx reverse proxy for web access (ports 80/443)
- **mailu-admin**: Web administration interface (port 80)
- **mailu-smtp**: Postfix SMTP server (ports 25/587)
- **mailu-imap**: Dovecot IMAP server (ports 143/993)
- **mailu-antispam**: Rspamd spam filtering (ports 11333/11334)
- **mailu-redis**: Redis for session management (port 6379)
### Storage
- **mailu-data**: 10Gi PVC for mail storage
- **mailu-db**: 5Gi PVC for database
- **mailu-redis**: 1Gi PVC for Redis persistence
## Configuration
### Environment Variables
The Mailu stack is configured via the `mailu-configmap.yaml` file:
- **DOMAIN**: `bakewise.ai`
- **HOSTNAMES**: `mail.bakewise.ai`
- **RELAYHOST**: `smtp.mailgun.org:587`
- **RELAY_LOGIN**: `apikey`
- **TLS_FLAVOR**: `cert` (uses Let's Encrypt)
- **WEBMAIL**: `roundcube`
- **ANTIVIRUS**: `clamav`
- **ANTISPAM**: `rspamd`
### Secrets
Secrets are managed in `mailu-secrets.yaml`:
- **ADMIN_PASSWORD**: Base64 encoded admin password
- **SECRET_KEY**: Mailu internal encryption key
- **RELAY_PASSWORD**: External SMTP relay API key
- **DB_PASSWORD**: Database password
- **REDIS_PASSWORD**: Redis password
## Deployment
### Prerequisites
1. Kubernetes cluster with storage provisioner
2. Ingress controller (NGINX)
3. Cert-manager for TLS certificates
4. External SMTP relay account (Mailgun, SendGrid, AWS SES)
### Deployment Steps
1. **Configure DNS**:
```bash
# MX record for inbound email
bakewise.ai. IN MX 10 mail.bakewise.ai.
# A record for mail server
mail.bakewise.ai. IN A <your-ingress-ip>
# SPF record (authorize external relay)
bakewise.ai. IN TXT "v=spf1 include:mailgun.org ~all"
# DKIM record (Mailu generates this)
mailu._domainkey.bakewise.ai. IN TXT "v=DKIM1; k=rsa; p=<public-key>"
# DMARC record
_dmarc.bakewise.ai. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@bakewise.ai"
```
2. **Update secrets**:
```bash
# Generate secure passwords
echo -n "your-secure-password" | base64
openssl rand -base64 32
# Update mailu-secrets.yaml with real values
```
3. **Deploy Mailu**:
```bash
# For production
kubectl apply -k infrastructure/environments/prod/k8s-manifests/
# For development
kubectl apply -k infrastructure/environments/dev/k8s-manifests/
```
4. **Verify deployment**:
```bash
kubectl get pods -n bakery-ia | grep mailu
kubectl logs -f mailu-smtp-<pod-id> -n bakery-ia
```
## Integration with Notification Service
The notification service has been updated to use Mailu as the SMTP server:
```yaml
# infrastructure/environments/common/configs/configmap.yaml
SMTP_HOST: "mailu-smtp.bakery-ia.svc.cluster.local"
SMTP_PORT: "587"
SMTP_TLS: "true"
SMTP_SSL: "false"
```
## Accessing Mailu
### Web Interface
- **Admin Panel**: `https://mail.bakewise.ai/admin`
- **Webmail**: `https://mail.bakewise.ai/webmail`
### SMTP Configuration
For external clients to send email through Mailu:
- **Server**: `mail.bakewise.ai`
- **Port**: 587 (Submission)
- **Security**: STARTTLS
- **Authentication**: Required
### IMAP Configuration
For email clients to access mailboxes:
- **Server**: `mail.bakewise.ai`
- **Port**: 993 (IMAPS)
- **Security**: SSL/TLS
- **Authentication**: Required
## Monitoring and Maintenance
### Health Checks
```bash
# Check Mailu services
kubectl get pods -n bakery-ia -l app=mailu
# Check Mailu logs
kubectl logs -f mailu-smtp-<pod-id> -n bakery-ia
kubectl logs -f mailu-antispam-<pod-id> -n bakery-ia
# Check queue status
kubectl exec -it mailu-smtp-<pod-id> -n bakery-ia -- mailq
```
### Backup and Restore
```bash
# Backup mail data
kubectl exec -it mailu-smtp-<pod-id> -n bakery-ia -- tar czf /backup/mailu-backup-$(date +%Y%m%d).tar.gz /data
# Restore mail data
kubectl cp mailu-backup-<date>.tar.gz mailu-smtp-<pod-id>:/backup/ -n bakery-ia
kubectl exec -it mailu-smtp-<pod-id> -n bakery-ia -- tar xzf /backup/mailu-backup-<date>.tar.gz -C /
```
## Troubleshooting
### Common Issues
1. **SMTP Relay Authentication Failed**:
- Verify `RELAY_PASSWORD` in secrets matches your external relay API key
- Check network connectivity to external relay
2. **TLS Certificate Issues**:
- Ensure cert-manager is working properly
- Check DNS records are correctly pointing to your ingress
3. **Email Delivery Delays**:
- Check Mailu queue: `kubectl exec -it mailu-smtp-<pod-id> -n bakery-ia -- mailq`
- Verify external relay service status
4. **Spam Filtering Issues**:
- Check rspamd logs: `kubectl logs -f mailu-antispam-<pod-id> -n bakery-ia`
- Adjust spam scoring in rspamd configuration
## Resource Requirements
| Component | CPU Request | CPU Limit | Memory Request | Memory Limit | Storage |
|-----------|-------------|-----------|----------------|--------------|----------|
| mailu-front | 100m | 200m | 128Mi | 256Mi | - |
| mailu-admin | 100m | 300m | 256Mi | 512Mi | - |
| mailu-smtp | 100m | 500m | 256Mi | 512Mi | 10Gi |
| mailu-imap | 100m | 500m | 256Mi | 512Mi | - |
| mailu-antispam | 200m | 1000m | 512Mi | 1Gi | - |
| mailu-redis | 100m | 200m | 128Mi | 256Mi | 1Gi |
**Total**: ~600m CPU, ~1.7Gi Memory, 16Gi Storage
## Security Considerations
1. **Network Policies**: Mailu is protected by network policies that restrict access to only the notification service and ingress controller.
2. **TLS Encryption**: All external connections use TLS encryption.
3. **Authentication**: All services require authentication.
4. **Rate Limiting**: Configured to prevent abuse (60/hour per IP, 100/day per user).
5. **Spam Protection**: Rspamd provides comprehensive spam filtering with DKIM signing.
## Migration from External SMTP
To migrate from external SMTP (Gmail) to Mailu:
1. Update DNS records as shown above
2. Deploy Mailu stack
3. Update notification service configuration
4. Test email delivery
5. Monitor deliverability metrics
6. Gradually increase email volume
## External Relay Provider Comparison
| Provider | Pros | Cons | Free Tier |
|----------|------|------|-----------|
| SendGrid | Best deliverability, robust API | Expensive at scale | 100/day |
| Mailgun | Developer-friendly, good logs | EU data residency costs extra | 5,000/month (3 months) |
| AWS SES | Cheapest at scale ($0.10/1000) | Requires warm-up period | 62,000/month (from EC2) |
| Postmark | Transactional focus, fast | No marketing emails | 100/month |
**Recommendation**: AWS SES for cost-effectiveness and Kubernetes integration.
## Support
For issues with Mailu deployment:
1. Check the [Mailu documentation](https://mailu.io/)
2. Review Kubernetes events: `kubectl get events -n bakery-ia`
3. Check pod logs for specific components
4. Verify network connectivity and DNS resolution

View File

@@ -0,0 +1,265 @@
# Webmail DNS Configuration Guide
This guide provides the DNS configuration required to make the webmail system accessible from `webmail.bakewise.ai`.
## Production DNS Configuration
### Required DNS Records for `webmail.bakewise.ai`
```bash
# A Record for webmail subdomain
webmail.bakewise.ai. IN A <your-ingress-ip>
# CNAME Record (alternative approach)
webmail.bakewise.ai. IN CNAME bakewise.ai.
# MX Record for email delivery (if receiving emails)
bakewise.ai. IN MX 10 webmail.bakewise.ai.
# SPF Record (authorize webmail server)
bakewise.ai. IN TXT "v=spf1 include:mailgun.org ~all"
# DKIM Record (will be generated by Mailu)
mailu._domainkey.bakewise.ai. IN TXT "v=DKIM1; k=rsa; p=<public-key>"
# DMARC Record
_dmarc.bakewise.ai. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@bakewise.ai"
```
## Development DNS Configuration
### Required DNS Records for `webmail.bakery-ia.local`
For local development, add these entries to your `/etc/hosts` file:
```bash
# Add to /etc/hosts
127.0.0.1 webmail.bakery-ia.local
127.0.0.1 bakery-ia.local
127.0.0.1 monitoring.bakery-ia.local
```
## TLS Certificate Configuration
The ingress configuration includes automatic TLS certificate provisioning using cert-manager with Let's Encrypt.
### Production TLS Configuration
The production ingress (`prod-ingress.yaml`) includes:
```yaml
tls:
- hosts:
- bakewise.ai
- monitoring.bakewise.ai
- webmail.bakewise.ai # ← Added webmail domain
secretName: bakery-ia-prod-tls-cert
```
### Development TLS Configuration
The development ingress (`dev-ingress.yaml`) includes:
```yaml
tls:
- hosts:
- localhost
- bakery-ia.local
- monitoring.bakery-ia.local
- webmail.bakery-ia.local # ← Added webmail domain
secretName: bakery-dev-tls-cert
```
## Ingress Routing Configuration
### Production Routing
The production ingress routes traffic as follows:
- `https://bakewise.ai/` → Frontend service (port 3000)
- `https://bakewise.ai/api/` → Gateway service (port 8000)
- `https://monitoring.bakewise.ai/` → SigNoz monitoring (port 8080)
- `https://webmail.bakewise.ai/` → Email webmail (port 80)
- `https://webmail.bakewise.ai/webmail` → Email webmail
- `https://webmail.bakewise.ai/admin` → Email admin interface
### Development Routing
The development ingress routes traffic as follows:
- `https://localhost/` → Frontend service (port 3000)
- `https://localhost/api/` → Gateway service (port 8000)
- `https://bakery-ia.local/` → Frontend service (port 3000)
- `https://bakery-ia.local/api/` → Gateway service (port 8000)
- `https://monitoring.bakery-ia.local/` → SigNoz monitoring (port 8080)
- `https://webmail.bakery-ia.local/` → Email webmail (port 80)
- `https://webmail.bakery-ia.local/webmail` → Email webmail
- `https://webmail.bakery-ia.local/admin` → Email admin interface
## Security Headers
The webmail ingress includes enhanced security headers:
```nginx
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';
connect-src 'self'; frame-src 'self';
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
```
## Deployment Steps
### 1. Update DNS Records
```bash
# For production (using Cloudflare as example)
cfcli dns create bakewise.ai A webmail <ingress-ip> --ttl 3600 --proxied
# For development (add to /etc/hosts)
echo "127.0.0.1 webmail.bakery-ia.local" | sudo tee -a /etc/hosts
```
### 2. Apply Ingress Configuration
```bash
# Apply the updated ingress configuration
kubectl apply -k infrastructure/environments/prod/k8s-manifests/
# Verify the ingress is configured correctly
kubectl get ingress -n bakery-ia
kubectl describe ingress bakery-ingress-prod -n bakery-ia
```
### 3. Verify TLS Certificates
```bash
# Check TLS certificate status
kubectl get certificaterequest -n bakery-ia
kubectl get certificate -n bakery-ia
# Check certificate details
kubectl describe certificate bakery-ia-prod-tls-cert -n bakery-ia
```
### 4. Test Webmail Access
```bash
# Test webmail accessibility
curl -I https://webmail.bakewise.ai
curl -I https://webmail.bakewise.ai/webmail
curl -I https://webmail.bakewise.ai/admin
# Test from browser
open https://webmail.bakewise.ai
```
## Troubleshooting
### DNS Issues
```bash
# Check DNS resolution
dig webmail.bakewise.ai
nslookup webmail.bakewise.ai
# Check ingress controller logs
kubectl logs -f -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
```
### TLS Issues
```bash
# Check cert-manager logs
kubectl logs -f -n cert-manager -l app=cert-manager
# Check certificate status
kubectl get certificaterequest,certificate,order,challenge -n bakery-ia
```
### Ingress Issues
```bash
# Check ingress controller events
kubectl get events -n ingress-nginx
# Check ingress description
kubectl describe ingress -n bakery-ia
```
## Monitoring and Maintenance
### Check Webmail Service Status
```bash
# Check email services
kubectl get pods -n bakery-ia -l app=email
# Check webmail service
kubectl get service email-webmail -n bakery-ia
# Check ingress routing
kubectl get ingress -n bakery-ia -o yaml | grep -A 10 webmail
```
### Update DNS Records
When the ingress IP changes, update the DNS records:
```bash
# Get current ingress IP
kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
# Update DNS (Cloudflare example)
cfcli dns update bakewise.ai A webmail <new-ip> --ttl 3600 --proxied
```
## Access Information
After configuration, the webmail system will be accessible at:
- **Production**: `https://webmail.bakewise.ai`
- **Development**: `https://webmail.bakery-ia.local`
Default credentials (configured in secrets):
- **Admin**: `admin@bakewise.ai`
- **Password**: Configured in `email-secrets`
## Integration with Existing Systems
The webmail system integrates with:
1. **SMTP Service**: `email-smtp.bakery-ia.svc.cluster.local:587`
2. **IMAP Service**: `email-imap.bakery-ia.svc.cluster.local:993`
3. **Notification Service**: Uses the new SMTP service for email notifications
4. **Monitoring**: SigNoz alerts use the new email service
## Backup and Recovery
### DNS Backup
```bash
# Export DNS records (Cloudflare example)
cfcli dns export bakewise.ai > dns-backup.json
# Restore DNS records
cfcli dns import bakewise.ai dns-backup.json
```
### Certificate Backup
```bash
# Export TLS secrets
kubectl get secret bakery-ia-prod-tls-cert -n bakery-ia -o yaml > tls-backup.yaml
# Restore TLS secrets
kubectl apply -f tls-backup.yaml
```
## References
- [Cert-manager Documentation](https://cert-manager.io/docs/)
- [NGINX Ingress Controller](https://kubernetes.github.io/ingress-nginx/)
- [Let's Encrypt](https://letsencrypt.org/)
- [DNS Configuration Best Practices](https://www.cloudflare.com/learning/dns/)
This configuration provides a secure, scalable webmail solution that integrates seamlessly with the existing Bakery-IA infrastructure.

View File

@@ -0,0 +1,24 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bakery-ia
resources:
- mailu-configmap.yaml
- mailu-secrets.yaml
- mailu-pvc.yaml
- mailu-deployment.yaml
- mailu-services.yaml
- mailu-antispam.yaml
- mailu-networkpolicy.yaml
# NOTE: mailu-ingress.yaml removed - ingress is now centralized in platform/networking
# NOTE: mailu-replacement.yaml removed - using official Mailu stack
# NOTE: email-config.yaml removed - configuration consolidated into mailu-configmap.yaml
# NOTE: Network policy kept here for self-contained module (could be moved to global security)
# NOTE: Mailu uses shared Redis (redis-service) with database 15 - no separate Redis needed
labels:
- includeSelectors: true
pairs:
app: mailu
platform: mail
managed-by: kustomize

View File

@@ -0,0 +1,48 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mailu-antispam
namespace: bakery-ia
labels:
app: mailu
component: antispam
spec:
replicas: 1
selector:
matchLabels:
app: mailu
component: antispam
template:
metadata:
labels:
app: mailu
component: antispam
spec:
containers:
- name: antispam
image: ghcr.io/mailu/rspamd:2024.06
imagePullPolicy: IfNotPresent
ports:
- containerPort: 11333
name: rspamd
- containerPort: 11334
name: rspamd-admin
envFrom:
- configMapRef:
name: mailu-config
- secretRef:
name: mailu-secrets
volumeMounts:
- name: mailu-data
mountPath: /data
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
volumes:
- name: mailu-data
persistentVolumeClaim:
claimName: mailu-data

View File

@@ -0,0 +1,79 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: mailu-config
namespace: bakery-ia
labels:
app: mailu
component: config
data:
# Domain configuration
DOMAIN: "bakewise.ai"
HOSTNAMES: "mail.bakewise.ai"
POSTMASTER: "admin"
# Kubernetes-specific settings
# These help Mailu components discover each other in K8s
FRONT_ADDRESS: "mailu-front.bakery-ia.svc.cluster.local"
ADMIN_ADDRESS: "mailu-admin.bakery-ia.svc.cluster.local"
SMTP_ADDRESS: "mailu-smtp.bakery-ia.svc.cluster.local"
IMAP_ADDRESS: "mailu-imap.bakery-ia.svc.cluster.local"
ANTISPAM_ADDRESS: "mailu-antispam.bakery-ia.svc.cluster.local"
# Redis Configuration - Using shared cluster Redis (database 15 reserved for Mailu)
# The shared Redis has 16 databases (0-15), Mailu uses db 15 for isolation
# Using plain TCP port 6380 for internal cluster communication (TLS on 6379 for external)
# Primary configuration: Redis URL is configured in mailu-secrets.yaml as REDIS_URL
# Format: redis://:password@host:port/db
# Fallback configuration: REDIS_ADDRESS, REDIS_DB, and REDIS_PW
REDIS_ADDRESS: "redis-service.bakery-ia.svc.cluster.local:6380"
REDIS_DB: "15"
# REDIS_PW is set from secrets for Redis authentication
# External SMTP Relay Configuration
# Mailu relays outbound emails through an external service for better deliverability
# Supported providers: Mailgun, SendGrid, AWS SES, Postmark
#
# Provider RELAYHOST examples:
# Mailgun: [smtp.mailgun.org]:587
# SendGrid: [smtp.sendgrid.net]:587
# AWS SES: [email-smtp.us-east-1.amazonaws.com]:587
# Postmark: [smtp.postmarkapp.com]:587
#
# IMPORTANT: Update RELAY_PASSWORD in mailu-secrets.yaml with your provider's API key
RELAYHOST: "[smtp.mailgun.org]:587"
RELAY_LOGIN: "postmaster@bakewise.ai"
# Security settings
TLS_FLAVOR: "cert"
AUTH_RATELIMIT_IP: "60/hour"
AUTH_RATELIMIT_USER: "100/day"
# Message limits
MESSAGE_SIZE_LIMIT: "52428800" # 50MB
MESSAGE_RATELIMIT: "200/day"
# Features - disable ClamAV in dev to save resources (enable in prod)
WEBMAIL: "roundcube"
ANTIVIRUS: "none"
ANTISPAM: "rspamd"
# Postfix configuration
POSTFIX_MESSAGE_SIZE_LIMIT: "52428800"
POSTFIX_QUEUE_MINIMUM: "1"
POSTFIX_QUEUE_LIFETIME: "7d"
# DKIM configuration
DKIM_SELECTOR: "mailu"
DKIM_KEY_LENGTH: "2048"
# Webmail settings
WEB_WEBMAIL: "/webmail"
WEB_ADMIN: "/admin"
WEBMAIL_ADMIN: "admin@bakewise.ai"
# Logging
LOG_LEVEL: "INFO"
# Disable welcome email during development
WELCOME: "false"

View File

@@ -0,0 +1,208 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mailu-front
namespace: bakery-ia
labels:
app: mailu
component: front
spec:
replicas: 1
selector:
matchLabels:
app: mailu
component: front
template:
metadata:
labels:
app: mailu
component: front
spec:
containers:
- name: front
image: ghcr.io/mailu/nginx:2024.06
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
- containerPort: 443
name: https
envFrom:
- configMapRef:
name: mailu-config
- secretRef:
name: mailu-secrets
volumeMounts:
- name: mailu-data
mountPath: /data
- name: mailu-tls
mountPath: /certs
readOnly: true
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
volumes:
- name: mailu-data
persistentVolumeClaim:
claimName: mailu-data
- name: mailu-tls
secret:
# TLS secret name is environment-specific:
# - Dev: bakery-dev-tls-cert (self-signed, from dev-certificate.yaml)
# - Prod: bakery-ia-prod-tls-cert (Let's Encrypt, from prod-certificate.yaml)
# Patched via kustomize overlays in dev/prod kustomization.yaml
secretName: MAILU_TLS_SECRET_PLACEHOLDER
items:
- key: tls.crt
path: cert.pem
- key: tls.key
path: key.pem
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mailu-admin
namespace: bakery-ia
labels:
app: mailu
component: admin
spec:
replicas: 1
selector:
matchLabels:
app: mailu
component: admin
template:
metadata:
labels:
app: mailu
component: admin
spec:
containers:
- name: admin
image: ghcr.io/mailu/admin:2024.06
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
envFrom:
- configMapRef:
name: mailu-config
- secretRef:
name: mailu-secrets
volumeMounts:
- name: mailu-data
mountPath: /data
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 300m
memory: 512Mi
volumes:
- name: mailu-data
persistentVolumeClaim:
claimName: mailu-data
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mailu-smtp
namespace: bakery-ia
labels:
app: mailu
component: smtp
spec:
replicas: 1
selector:
matchLabels:
app: mailu
component: smtp
template:
metadata:
labels:
app: mailu
component: smtp
spec:
containers:
- name: smtp
image: ghcr.io/mailu/postfix:2024.06
imagePullPolicy: IfNotPresent
ports:
- containerPort: 25
name: smtp
- containerPort: 587
name: submission
envFrom:
- configMapRef:
name: mailu-config
- secretRef:
name: mailu-secrets
volumeMounts:
- name: mailu-data
mountPath: /data
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: mailu-data
persistentVolumeClaim:
claimName: mailu-data
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mailu-imap
namespace: bakery-ia
labels:
app: mailu
component: imap
spec:
replicas: 1
selector:
matchLabels:
app: mailu
component: imap
template:
metadata:
labels:
app: mailu
component: imap
spec:
containers:
- name: imap
image: ghcr.io/mailu/dovecot:2024.06
imagePullPolicy: IfNotPresent
ports:
- containerPort: 143
name: imap
- containerPort: 993
name: imaps
envFrom:
- configMapRef:
name: mailu-config
- secretRef:
name: mailu-secrets
volumeMounts:
- name: mailu-data
mountPath: /data
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: mailu-data
persistentVolumeClaim:
claimName: mailu-data

View File

@@ -0,0 +1,93 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mailu-network-policy
namespace: bakery-ia
labels:
app: mailu
component: network-policy
spec:
# Apply to all Mailu pods (matches mailu-deployment.yaml labels)
podSelector:
matchLabels:
app: mailu
policyTypes:
- Ingress
- Egress
ingress:
# Allow SMTP from notification-service
- from:
- podSelector:
matchLabels:
app: notification-service
ports:
- port: 25
- port: 587
# Allow SMTP from other internal services that may need to send email
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: bakery-ia
ports:
- port: 587
# Allow webmail/admin access via ingress controller
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- port: 80
- port: 443
# Allow internal Mailu component communication
- from:
- podSelector:
matchLabels:
app: mailu
ports:
- port: 25
- port: 587
- port: 143
- port: 993
- port: 80
- port: 11333
- port: 11334
egress:
# Allow relay to external SMTP (Mailgun)
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ports:
- port: 587
- port: 465
- port: 25
# Allow internal Mailu component communication
- to:
- podSelector:
matchLabels:
app: mailu
ports:
- port: 25
- port: 587
- port: 143
- port: 993
- port: 80
- port: 11333
- port: 11334
# Allow connection to shared Redis (database 15)
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: redis
ports:
- port: 6379
# Allow DNS lookups
- to: []
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

View File

@@ -0,0 +1,21 @@
# Mailu data storage - shared across all Mailu components
# Contains: mail data, SQLite database, DKIM keys, SSL certificates, queue
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mailu-data
namespace: bakery-ia
labels:
app: mailu
component: storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# NOTE: Change storageClassName based on your cluster's storage provisioner
# For local development (kind): standard
# For AWS EKS: gp2 or gp3
# For GKE: standard or premium-rwo
# For AKS: managed-premium or managed-csi

View File

@@ -0,0 +1,37 @@
apiVersion: v1
kind: Secret
metadata:
name: mailu-secrets
namespace: bakery-ia
labels:
app: mailu
component: secrets
type: Opaque
data:
# Admin credentials (base64 encoded)
# IMPORTANT: Replace with real credentials before production deployment
# Generate with: openssl rand -base64 24 | tr -d '\n' | base64
ADMIN_PASSWORD: "VzJYS2tSdUxpT25ZS2RCWVFTQXJvbjFpeWtFU1M1b2I=" # W2XKkRuLiOnYKdBYQSAron1iykESS5ob
# Mailu secret key for internal encryption
# Generate with: openssl rand -base64 32
SECRET_KEY: "Y2I2MWI5MzRkNDcwMjlhNjQxMTdjMGU0MTEwYzkzZjY2YmJjZjVlYWExNWM4NGM0MjcyN2ZhZDc4Zjc=" # cb61b934d47029a64117c0e4110c93f66bbcf5eaa15c84c42727fad78f7
# External SMTP relay credentials (Mailgun)
# For Mailgun: use postmaster@domain as username
RELAY_USER: "cG9zdG1hc3RlckBiYWtld2lzZS5haQ==" # postmaster@bakewise.ai
RELAY_PASSWORD: "bWFpbGd1bi1hcGkta2V5LXJlcGxhY2UtaW4tcHJvZHVjdGlvbg==" # mailgun-api-key-replace-in-production
# Database credentials
DB_PASSWORD: "RThLejQ3WW1WekRsSEdzMU05d0FiSnp4Y0tuR09OQ1Q=" # E8Kz47YmVzDlHGs1M9wAbJzxcKnGONCT
# Dovecot admin password (moved from ConfigMap for security)
DOVEADM_PASSWORD: "WnZhMzNoaVBJc2ZtV3RxUlBWV29taTRYZ2xLTlZPcHY=" # Zva33hiPIsfmWtqRPVWomi4XglKNVOpv
# Redis password - same as shared cluster Redis (redis-secrets)
# Mailu uses database 15 for isolation from other services
# REDIS_PW is required by Mailu for Redis authentication
REDIS_PASSWORD: "SjNsa2x4cHU5QzlPTElLdkJteFVIT2h0czFnc0lvM0E=" # J3lklxpu9C9OLIKvBmxUHOhts1gsIo3A
REDIS_PW: "SjNsa2x4cHU5QzlPTElLdkJteFVIT2h0czFnc0lvM0E=" # J3lklxpu9C9OLIKvBmxUHOhts1gsIo3A
# Redis URL for Mailu - using plain TCP port 6380 for internal cluster communication
REDIS_URL: "cmVkaXM6Ly86SjNsa2x4cHU5QzlPTElLdkJteFVIT2h0czFnc0lvM0FAcmVkaXMtc2VydmljZS5iYWtlcnktaWEuc3ZjLmNsdXN0ZXIubG9jYWw6NjM4MC8xNQ==" # redis://:J3lklxpu9C9OLIKvBmxUHOhts1gsIo3A@redis-service.bakery-ia.svc.cluster.local:6380/15

View File

@@ -0,0 +1,126 @@
# Mailu Services - Routes traffic to Mailu stack components
# All services use app: mailu selectors to match mailu-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: mailu-front
namespace: bakery-ia
labels:
app: mailu
component: front
spec:
type: ClusterIP
selector:
app: mailu
component: front
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
---
apiVersion: v1
kind: Service
metadata:
name: mailu-admin
namespace: bakery-ia
labels:
app: mailu
component: admin
spec:
type: ClusterIP
selector:
app: mailu
component: admin
ports:
- name: http
port: 80
targetPort: 80
---
# Primary SMTP service - used by notification-service and other internal services
apiVersion: v1
kind: Service
metadata:
name: mailu-smtp
namespace: bakery-ia
labels:
app: mailu
component: smtp
spec:
type: ClusterIP
selector:
app: mailu
component: smtp
ports:
- name: smtp
port: 25
targetPort: 25
- name: submission
port: 587
targetPort: 587
---
# Alias for backwards compatibility with services expecting 'email-smtp'
apiVersion: v1
kind: Service
metadata:
name: email-smtp
namespace: bakery-ia
labels:
app: mailu
component: smtp
spec:
type: ClusterIP
selector:
app: mailu
component: smtp
ports:
- name: smtp
port: 25
targetPort: 25
- name: submission
port: 587
targetPort: 587
---
apiVersion: v1
kind: Service
metadata:
name: mailu-imap
namespace: bakery-ia
labels:
app: mailu
component: imap
spec:
type: ClusterIP
selector:
app: mailu
component: imap
ports:
- name: imap
port: 143
targetPort: 143
- name: imaps
port: 993
targetPort: 993
---
apiVersion: v1
kind: Service
metadata:
name: mailu-antispam
namespace: bakery-ia
labels:
app: mailu
component: antispam
spec:
type: ClusterIP
selector:
app: mailu
component: antispam
ports:
- name: rspamd
port: 11333
targetPort: 11333
- name: rspamd-admin
port: 11334
targetPort: 11334