Authentication Flows

Understanding authentication mechanisms in cdk8s-mailu deployments.

Introduction

cdk8s-mailu uses multiple authentication mechanisms depending on the access path and component. Understanding these flows is crucial for security configuration and troubleshooting access issues.

Authentication Methods

nginx auth_http Protocol (Mail Clients)

Used for: Authenticated SMTP submission (587/465) and IMAP/POP3 access (993/995) from mail clients (Thunderbird, Outlook, mobile apps).

How it works:

  1. Client Connection: Mail client connects to Traefik on port 587, 465, 993, or 995

  2. TLS Termination: Traefik decrypts TLS and forwards plaintext connection to Front (Nginx)

  3. Authentication Subrequest: Before proxying to backend, Nginx makes an HTTP subrequest to Admin

    • URL: http://admin-service:8080/internal/auth/email

    • Headers: Auth-User, Auth-Pass, Auth-Protocol, Client-IP

  4. Credential Validation: Admin queries PostgreSQL/SQLite for user credentials

  5. Response:

    • Success (HTTP 200): Admin returns backend server address in Auth-Status: OK header

    • Failure (HTTP 403): Admin returns Auth-Status: Invalid credentials

  6. Backend Routing: If authenticated, Nginx proxies connection to appropriate backend:

    • SMTP (587/465) → Postfix:25

    • IMAP (993/143) → Dovecot:143

    • POP3 (995/110) → Dovecot:110

Key Points:

  • Authentication happens on every connection (not just once)

  • Credentials never reach the backend services (Front handles auth)

  • Admin acts as centralized authentication backend for all protocols

  • Uses standard SMTP/IMAP/POP3 username/password authentication

Configuration:

  • Implemented in nginx-patch-configmap.ts via auth_http directive

  • TLS_FLAVOR=notls ensures Front receives plaintext after Traefik TLS termination

  • Admin endpoint /internal/auth/email is internal-only (not exposed via Ingress)

Code Reference:

// src/constructs/nginx-patch-configmap.ts
server {
  listen 587;
  auth_http http://admin-service:8080/internal/auth/email;
  proxy_pass postfix-service:25;
}

SSO Integration (Webmail)

Used for: Roundcube webmail access via browser.

How it works:

  1. User Access: User navigates to https://mail.example.com/webmail in browser

  2. SSO Check: Webmail (Roundcube) checks for existing SSO session via Admin

  3. Login Prompt: If no session, Webmail redirects to Admin login page

  4. Admin Authentication: User enters credentials, Admin validates against database

  5. Session Creation: Admin creates SSO session (stored in PostgreSQL/SQLite)

  6. Redirect Back: Admin redirects user back to Webmail with session token

  7. Session Validation: Webmail validates session token with Admin

  8. Access Granted: User accesses webmail interface

Key Points:

  • Single Sign-On: Login once, access both Admin and Webmail

  • Session-based: Browser cookie maintains authentication state

  • Shared database: Admin and Webmail use same PostgreSQL database for session storage

  • No password re-entry: Webmail trusts Admin’s authentication

Configuration:

  • Webmail environment variable: ADMIN_ADDRESS points to Admin service

  • Admin environment variables: WEB_ADMIN='/admin' and WEB_WEBMAIL='/webmail' configure URL paths

  • Session storage: PostgreSQL (production) or SQLite (development)

  • Default URLs: https://mail.example.com/admin and https://mail.example.com/webmail

Database Tables:

  • user - User accounts and credentials

  • domain - Email domains

  • Admin SSO session table (managed by Mailu Admin)

Network Isolation Trust (Dovecot-Submission)

Used for: Webmail sending emails (Roundcube → Dovecot-Submission → Postfix).

How it works:

  1. User Composes Email: User writes email in Roundcube web interface

  2. Session Already Authenticated: User already logged in via Admin SSO

  3. Webmail → Dovecot-Submission: Roundcube connects to dovecot-submission-service:10025

  4. Trust Model: Dovecot-Submission accepts connection without password validation

    • Configuration: auth_mechanisms = plain with nopassword=y

    • Trust basis: Only webmail pod can reach this service (Kubernetes NetworkPolicy)

  5. Relay to Postfix: Dovecot-Submission relays message to Postfix:25

  6. Delivery: Postfix delivers to recipient’s MX server

Key Points:

  • Not actual token authentication: Despite documentation mentioning “tokens”, this is network isolation trust

  • Network isolation: Dovecot-Submission:10025 only accessible from webmail namespace/pods

  • No credential storage: Webmail doesn’t store user passwords

  • Session-based trust: User authenticated to webmail session = trusted sender

  • Separate from Front: Webmail bypasses Front/Nginx entirely for sending

Why This Architecture?

The separate dovecot-submission service exists because:

  1. Front’s bundled dovecot was not configurable for this use case

  2. Webmail needs to send without prompting for password again

  3. Network isolation provides security (only webmail can access submission port)

  4. Simplifies webmail configuration (no complex credential management)

Configuration:

Dovecot-Submission service configuration (ConfigMap):

# Dovecot submission configuration
auth_mechanisms = plain
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = dovecot
  }
}
# Network isolation trust
passdb {
  driver = static
  args = nopassword=y allow_nets=0.0.0.0/0
}

Webmail environment variable:

SUBMISSION_HOST=dovecot-submission-service
SUBMISSION_PORT=10025

Code Reference:

  • src/constructs/dovecot-submission-construct.ts - Separate submission service

  • src/constructs/webmail-construct.ts - Webmail SUBMISSION_HOST configuration

MX Mail Reception (No Authentication)

Used for: Receiving inbound email from internet mail servers.

How it works:

  1. External MTA → Traefik:25: Internet mail server connects to your MX record

  2. Traefik → Postfix:25: Traefik routes directly to Postfix (bypasses Front/Nginx)

  3. No Authentication Required: SMTP MX reception is unauthenticated by design (RFC 5321)

  4. Spam Filtering: Postfix calls Rspamd for spam/virus scanning

  5. Delivery: If accepted, Postfix delivers via LMTP to Dovecot:2525

Key Points:

  • No credentials required: MX reception must accept from any sender

  • Bypasses Front: Port 25 traffic goes directly to Postfix

  • Spam protection: Rspamd provides spam/virus filtering instead of authentication

  • Rate limiting: Traefik InFlightConn + Postfix anvil limits prevent abuse

Configuration:

  • Traefik IngressRouteTCP for port 25 routes directly to Postfix service

  • Postfix configuration: smtpd_relay_restrictions controls who can relay

  • No nginx auth_http on port 25

Authentication Flow Comparison

Access Path

Method

Authentication

Backend

Notes

Mail client SMTP (587/465)

nginx auth_http

Username/password

Admin:8080 → Postfix:25

Every connection authenticated

Mail client IMAP/POP3 (993/995)

nginx auth_http

Username/password

Admin:8080 → Dovecot:143/110

Every connection authenticated

Webmail access (HTTPS)

SSO session

Username/password (first login)

Admin database

Session cookie for subsequent access

Webmail sending (SMTP)

Network isolation

None (trust)

Dovecot-Submission:10025 → Postfix:25

Webmail session = trusted

MX mail (port 25)

None

None

Postfix:25 directly

Standard SMTP, spam filtering only

Security Considerations

Credential Storage

  • User passwords: Hashed in PostgreSQL/SQLite (bcrypt or similar)

  • Admin credentials: Never stored in Kubernetes Secrets (only in database)

  • Webmail: No password storage (relies on Admin SSO session)

  • API token: Optional, stored in Secret if API enabled

Network Security

  • TLS Termination: Traefik handles all TLS (HTTPS, SMTPS, IMAPS, POP3S)

  • Plaintext backends: All backend services receive plaintext (TLS_FLAVOR=notls)

  • Internal traffic: Kubernetes service mesh (no encryption needed within cluster)

  • Dovecot-Submission isolation: Only webmail namespace can access port 10025

Authentication Best Practices

  1. Use PostgreSQL in production: SQLite suitable only for small deployments

  2. Enable strong passwords: Configure password complexity requirements in Admin

  3. Monitor auth failures: Watch Admin logs for brute-force attempts

  4. Rate limiting: Configure Traefik and Postfix rate limits

  5. API token protection: If enabling API, use strong random token in Secret

Troubleshooting Authentication Issues

Mail Client Authentication Failures

Symptoms: “Invalid credentials” or “Authentication failed” in mail client

Check:

  1. Verify credentials in Admin web UI (https://admin.example.com)

  2. Check Admin logs for auth_http requests:

    kubectl logs -n mailu deployment/admin-deployment | grep auth/email
    
  3. Verify Front can reach Admin:

    kubectl exec -n mailu deployment/front-deployment -- curl http://admin-service:8080/internal/auth/email
    
  4. Check database connectivity (PostgreSQL or SQLite)

Webmail Login Failures

Symptoms: Cannot login to webmail, or login page redirects loop

Check:

  1. Verify SSO configuration in Admin environment variables:

    kubectl get deployment admin-deployment -n mailu -o jsonpath='{.spec.template.spec.containers[0].env}' | grep -E 'WEB_ADMIN|WEB_WEBMAIL'
    
  2. Check database connection (Admin and Webmail share database)

  3. Verify session storage is working (check Admin logs)

  4. Clear browser cookies and retry

Webmail Sending Failures

Symptoms: Cannot send email from webmail, but receiving works

Check:

  1. Verify dovecot-submission service is running:

    kubectl get pods -n mailu | grep dovecot-submission
    
  2. Check Webmail can reach dovecot-submission:

    kubectl exec -n mailu deployment/webmail-deployment -- nc -zv dovecot-submission-service 10025
    
  3. Check dovecot-submission logs:

    kubectl logs -n mailu deployment/dovecot-submission-deployment
    
  4. Verify SUBMISSION_HOST environment variable in Webmail

MX Reception Issues

Symptoms: Cannot receive email from internet

Check:

  1. Verify MX DNS records point to your server

  2. Check Traefik IngressRouteTCP for port 25:

    kubectl get ingressroutetcp -A
    
  3. Test SMTP from external server:

    telnet mail.example.com 25
    
  4. Check Postfix logs for delivery errors:

    kubectl logs -n mailu deployment/postfix-deployment | grep 'status='
    

See Also