Secure Access Platform Architecture

Architecture decision record for the secure access platform: Cloudflare Tunnel to Traefik to Authentik on Proxmox, covering trust boundaries, threat model, and operational design.

Status

Accepted — Deployed and operational since Q4 2025. Revised January 2026 to include Cloudflare Access policy updates.

Context

Running self-hosted services requires a secure, maintainable method for external access. The platform must handle multiple trust levels (admin-only, team-shared, public-facing) without exposing the underlying infrastructure to the internet.

Requirements

  1. No public IP exposure — The network perimeter should not have open inbound ports
  2. Per-service access control — Each application gets its own authentication and authorization policy
  3. Single sign-on — Users authenticate once and access all authorized services
  4. Centralized identity — One identity provider for all services, with group-based policies
  5. Defense in depth — Multiple layers of security, no single point of failure for access control
  6. Operational simplicity — Adding or removing services should not require infrastructure changes

Constraints

  • All services run on a single Proxmox VE hypervisor
  • Budget is homelab-scale (minimize paid dependencies)
  • Must support both web applications and TCP/SSH access
  • The operator (me) is the primary admin; occasional shared access for specific services

Decision

Implement a layered access architecture using Cloudflare Tunnels for transport, Traefik for routing, and Authentik for identity management, all running on Proxmox VE.

Architecture Overview

                    Internet
                       │
                       ▼
              ┌─────────────────┐
              │  Cloudflare Edge │
              │  (WAF, DDoS,    │
              │   TLS termination)│
              └────────┬────────┘
                       │ Tunnel (outbound only)
                       ▼
              ┌─────────────────┐
              │   cloudflared    │
              │  (tunnel agent)  │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │     Traefik      │
              │  (reverse proxy, │
              │   middleware,    │
              │   TLS internal)  │
              └────────┬────────┘
                       │ Forward Auth
                       ▼
              ┌─────────────────┐
              │    Authentik     │
              │  (identity,     │
              │   SSO, policies) │
              └────────┬────────┘
                       │ Authenticated
                       ▼
              ┌─────────────────┐
              │  Target Service  │
              │  (Grafana, etc.) │
              └─────────────────┘

Component Responsibilities

Component Responsibility Trust Level
Cloudflare Edge DDoS protection, WAF, TLS termination, bot mitigation External boundary
cloudflared Outbound tunnel transport, route mapping Transport
Traefik Request routing, middleware chain, internal TLS Internal routing
Authentik Authentication, authorization, SSO, group policies Identity
Target Service Application logic Application

Trust Boundaries

Boundary 1: Internet to Cloudflare Edge

This is the outermost trust boundary. All traffic from the internet passes through Cloudflare before reaching any infrastructure component.

Threats mitigated:

  • DDoS attacks (Cloudflare absorbs volumetric attacks)
  • Known exploit patterns (WAF rules)
  • Bot traffic (challenge pages, rate limiting)
  • Direct IP scanning (no public IP exposed)

Residual risk: Cloudflare itself is a trust dependency. A compromise of Cloudflare's infrastructure could theoretically expose traffic content. Mitigated by the fact that Authentik adds its own authentication layer independent of Cloudflare.

Boundary 2: Cloudflare Tunnel to Traefik

The tunnel carries traffic from Cloudflare's edge to the internal Traefik instance. This is an outbound-only connection established by cloudflared.

Threats mitigated:

  • Port scanning (no inbound ports open)
  • Man-in-the-middle (tunnel uses authenticated, encrypted transport)
  • Unauthorized tunnel creation (tunnel credentials are unique per installation)

Residual risk: If the tunnel credentials are compromised, an attacker could potentially establish a rogue tunnel. Mitigated by storing credentials as Docker secrets and restricting file permissions.

Boundary 3: Traefik to Authentik

Every request to a protected service passes through Traefik's forward-auth middleware, which calls Authentik to verify the user's session.

Threats mitigated:

  • Unauthenticated access (every request is validated)
  • Session hijacking (Authentik manages session tokens with configurable expiry)
  • Privilege escalation (group-based policies restrict access per application)

Residual risk: A misconfigured Traefik router that omits the auth middleware would bypass Authentik entirely. Mitigated by using a default middleware chain and testing new routes in staging before production.

Boundary 4: Authentik to Target Service

After Authentik validates the user's identity and authorization, the request proceeds to the target service with identity headers injected by Authentik.

Threats mitigated:

  • Unauthorized application access (policy-gated)
  • Identity spoofing (headers are set by the trusted Authentik outpost, not the client)

Residual risk: If a service is accessible on the internal network without going through Traefik, the auth layer is bypassed. Mitigated by firewall rules that restrict inter-container communication to defined paths.

Deployment Topology

All components run as Docker containers on a Proxmox VM:

Proxmox VE Host
└── VM: docker-host (Ubuntu 24.04)
    ├── cloudflared (tunnel agent)
    ├── traefik (reverse proxy)
    ├── authentik-server (identity provider)
    ├── authentik-worker (background tasks)
    ├── postgresql (Authentik database)
    ├── redis (Authentik cache/sessions)
    └── [application containers]

Network Isolation

Docker networks provide isolation between components:

  • proxy — Shared network for Traefik, cloudflared, and services that need external routing
  • authentik-internal — Isolated network for Authentik server, worker, PostgreSQL, and Redis
  • monitoring — Separate network for observability tools (Grafana, Prometheus, Loki)

Services only join the networks they require. The PostgreSQL and Redis containers for Authentik are on the authentik-internal network only -- they are not reachable from the proxy network.

Security Posture

What is hardened

  • No inbound ports on the host firewall (all access via tunnel)
  • Docker containers run as non-root users where supported
  • Authentik enforces MFA for admin accounts
  • Traefik's dashboard is not exposed externally
  • PostgreSQL listens only on the Docker internal network
  • All secrets managed via Docker secrets, not environment variables
  • TLS between Traefik and backend services where the service supports it

What is monitored

  • Authentik login events (success and failure) forwarded to Wazuh
  • Traefik access logs ingested by Loki
  • Cloudflare analytics for edge-level traffic patterns
  • Container health checks with alerting on failure

What is not yet hardened

  • No network policy enforcement at the container level (planned: move to K3s with NetworkPolicies)
  • Authentik backup is manual (planned: automated PostgreSQL dumps to encrypted off-site storage)
  • No automated certificate rotation for internal TLS (planned: step-ca integration)

Alternatives Considered

VPN-only (WireGuard/Tailscale)

Rejected as the primary access method because it provides network-level access rather than application-level access. Still used for administrative SSH access to the hypervisor.

Nginx Proxy Manager

Rejected because it provides a GUI-first experience with limited automation capabilities. Traefik's Docker label integration and file-based configuration align better with infrastructure-as-code practices.

Authelia

Considered as an alternative to Authentik. Authelia is lighter weight but lacks Authentik's SCIM support, application management UI, and flexible policy engine. Authentik was chosen for its feature completeness at the cost of higher resource usage.

Direct Cloudflare Access (without Authentik)

Cloudflare Access provides its own identity-aware proxy. This was rejected because it creates a single-vendor dependency for both transport and identity. Running Authentik independently means the identity layer is portable and not tied to Cloudflare.

Consequences

Positive

  • Zero inbound ports reduces the attack surface to near zero
  • Adding new services is a configuration change, not an infrastructure change
  • SSO reduces credential fatigue and enables centralized audit logging
  • Multiple independent security layers (Cloudflare WAF, Authentik policies, service-level auth) provide defense in depth

Negative

  • Complexity is higher than a simple VPN setup
  • Cloudflare is a runtime dependency for external access
  • Authentik consumes non-trivial resources (~500MB RAM for server + worker + DB + cache)
  • Debugging authentication issues requires understanding three layers of middleware

Neutral

  • Operational cost is zero (all components are open source, Cloudflare free tier is sufficient)
  • The architecture is transferable to other environments (cloud VMs, Kubernetes) with minimal changes to the component configuration

Revision History

Date Change
2025-11-20 Initial architecture decision
2025-12-15 Added WireGuard as complementary admin access path
2026-01-05 Updated Cloudflare Access policy section, added monitoring details