This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Security Model
Loading…
Security Model
Relevant source files
Purpose and Scope
This document explains the security architecture of the Docker MQTT Mosquitto Cloudflare Tunnel system, including threat model, attack surface reduction, secret management, and network isolation mechanisms. It covers the security principles embedded in the system design and the trade-offs involved in the default configuration.
For operational deployment considerations including production hardening and monitoring, see Production Deployment Considerations. For authentication and access control configuration specifics, see Authentication and Access Control.
Core Security Principles
The system implements three foundational security principles:
| Principle | Implementation | Benefit |
|---|---|---|
| Zero Trust Network Access | Cloudflare Tunnel with outbound-only connections | Origin server has no exposed attack surface |
| Separation of Code and Secrets | .gitignore exclusion of .env file | Prevents credential leakage through version control |
| Defense in Depth | Multiple isolation layers (Cloudflare Edge, Docker network, container boundaries) | Compromising one layer does not expose entire system |
Zero Trust Architecture
The system inverts the traditional client-server model. Instead of the MQTT broker accepting inbound connections from the internet, the cloudflared container establishes a persistent outbound connection to Cloudflare’s network. External clients never connect directly to the origin server.
Sources : README.md:17, README.md:22, README.md:67
Attack Surface Analysis
Traditional MQTT Deployment vs. Cloudflare Tunnel Deployment
Eliminated Attack Vectors
The Cloudflare Tunnel architecture eliminates entire categories of attacks:
| Attack Type | Traditional Deployment | Tunnel Deployment |
|---|---|---|
| Port Scanning | Vulnerable - ports 1883 and 9001 discoverable | Immune - no listening ports on public internet |
| Direct DDoS | Vulnerable - origin server is attack target | Protected - Cloudflare absorbs attack |
| SSL/TLS Certificate Management | Required - operator manages certificates | Unnecessary - Cloudflare manages certificates |
| IP-based Access Control | Fragile - IP addresses change, easily spoofed | N/A - origin has no public IP exposure |
| Zero-day Exploits in Mosquitto | High impact - direct exploitation | Reduced impact - traffic filtered through Cloudflare WAF |
Sources : README.md:17, Diagram 1 (High-Level System Architecture), Diagram 3 (External Access and Security Flow)
Secret Management Model
Token-Based Authentication
The CLOUDFLARE_TUNNEL_TOKEN serves as the cryptographic secret that authenticates the cloudflared container to Cloudflare’s network. This token grants the right to route traffic for the configured tunnel.
stateDiagram-v2
[*] --> Generated : User creates tunnel in Cloudflare Dashboard
Generated --> Copied : Token displayed in UI
Copied --> Local : User creates .env file
state Local {
[*] --> FileCreated
FileCreated --> TokenAdded : Paste CLOUDFLARE_TUNNEL_TOKEN=...
TokenAdded --> GitignoreProtected : .gitignore prevents commit
}
Local --> Runtime : docker-compose reads .env
state Runtime {
[*] --> EnvLoaded
EnvLoaded --> ContainerStarted : Environment variable injected
ContainerStarted --> TunnelAuth : cloudflared authenticates
}
Runtime --> Operational : Tunnel established
state GitignoreProtected {
[*] --> CheckGitStatus
CheckGitStatus --> NotTracked : .env excluded
NotTracked --> [*]
}
Operational --> Rotated : Token rotation (manual)
Rotated --> Generated
note right of GitignoreProtected
Critical security boundary:
.env file must never be
committed to version control
end note
Secret Lifecycle
Version Control Protection
The repository implements multiple layers of protection against credential leakage:
| Protection Layer | Implementation | File Reference |
|---|---|---|
| Explicit exclusion | .gitignore contains .env | .gitignore1 |
| Template file | .env.sample shows format without secrets | .env.sample1 |
| Documentation | README instructs users to create .env manually | README.md53 |
The .gitignore file explicitly excludes the .env file containing the tunnel token:
.env
data/*
The .env.sample template provides structure without exposing actual credentials:
CLOUDFLARE_TUNNEL_TOKEN=your_token
Important : The .env.sample file is committed to version control as documentation. Operators must create their own .env file locally and populate it with their actual token.
Sources : .gitignore:1-2 .env.sample1 README.md53
Network Security Boundaries
Container Network Isolation
Security Boundaries Defined
| Boundary | Trust Level | Entry Requirements | Enforcement Mechanism |
|---|---|---|---|
| Public Internet → Cloudflare Edge | Untrusted → Trusted | TLS handshake, valid hostname | Cloudflare network infrastructure |
| Cloudflare Edge → Tunnel Infrastructure | Trusted → Trusted | Valid tunnel configuration | Cloudflare internal routing |
Tunnel Infrastructure → cloudflared container | Trusted → Trusted | CLOUDFLARE_TUNNEL_TOKEN authentication | Tunnel protocol cryptographic verification |
cloudflared container → mosquitto container | Trusted → Trusted | Docker internal DNS resolution | Docker bridge network isolation |
External clients → mosquitto container | Forbidden | N/A - no direct route exists | Docker network isolation, no port exposure |
Port Exposure Analysis
The docker-compose.yml configuration deliberately omits port mappings to the host system. Neither container exposes any ports outside the Docker bridge network:
This architectural decision ensures that:
- The Mosquitto broker is not accessible via the host’s network interfaces
- Port scanning of the host reveals no MQTT services
- Firewall rules on the host are irrelevant to MQTT access
- The only route to the broker is through the authenticated Cloudflare Tunnel
Sources : docker-compose.yml:1-19 mosquitto.conf:1-5 Diagram 2 (Docker Container Network Topology)
Authentication and Authorization
Default Configuration: Anonymous Access Allowed
The default mosquitto.conf configuration permits anonymous connections and does not enforce authentication:
listener 1883
protocol mqtt
listener 9001
protocol websockets
Security Implication : Any client that can reach the broker (via the Cloudflare Tunnel) can publish and subscribe to any topic without authentication.
graph LR
Client["Client with URL"]
subgraph CloudflareLayer["Cloudflare Layer - Transport Security"]
TLS["TLS Termination\nCertificate validation"]
WAF["Web Application Firewall\nOptional rules"]
end
subgraph MQTTLayer["MQTT Layer - Application Security"]
Anonymous["Anonymous access permitted\nNo username/password required"]
NoACL["No topic-level restrictions\nFull pub/sub access"]
end
Client -->|HTTPS connection| TLS
TLS -->|Decrypted, inspected| WAF
WAF -->|Forwarded if allowed| Anonymous
Anonymous -->|All operations permitted| NoACL
NoACL -->|Can publish to any topic| Topics["All MQTT Topics"]
NoACL -->|Can subscribe to any topic| Topics
Access Control Model
Security Trade-offs
| Security Feature | Default Configuration | Security Benefit | Operational Complexity |
|---|---|---|---|
| Anonymous access | Enabled | None - reduces security | Low - no credential management |
| Password authentication | Disabled | Would prevent unauthorized access | Medium - requires credential distribution |
| Topic-level ACLs | Not configured | Would limit topic access per client | High - requires ACL file management |
| TLS client certificates | Not configured | Would provide mutual TLS authentication | Very High - PKI infrastructure required |
Enhanced Security Branch
The repository includes an alternate configuration branch (protected-no-wildcard) that implements:
- Topic-based Access Control : ACL file restricts wildcard subscriptions and enforces username-based topic prefixes
- Encrypted Retained Messages : Uses
gocryptfsto encrypt persistent message storage - Auto-save retained messages : Ensures message persistence
This branch demonstrates production-grade security hardening. See Protected Branch Features for details.
Sources : mosquitto.conf:1-5 README.md:7-13
TLS and Encryption
Multi-layer Encryption Architecture
Encryption Scope
| Network Segment | Encryption Status | Justification |
|---|---|---|
| Client → Cloudflare Edge | Encrypted (TLS 1.3) | Public internet traversal requires encryption |
| Cloudflare Edge → Tunnel Infrastructure | Encrypted (Cloudflare proprietary) | Cloudflare’s internal network, encrypted by default |
Tunnel Infrastructure → cloudflared | Encrypted (Tunnel protocol) | Traverses internet between Cloudflare PoP and origin |
cloudflared → mosquitto | Unencrypted (HTTP) | Isolated Docker bridge network, no external exposure |
Rationale for unencrypted internal segment : The traffic between cloudflared and mosquitto occurs entirely within the Docker bridge network, which is isolated from external networks. Adding TLS to this segment would:
- Increase CPU overhead without security benefit
- Require certificate management for internal services
- Complicate debugging and troubleshooting
Sources : README.md:67-68 docker-compose.yml13 Diagram 3 (External Access and Security Flow)
Operational Security Considerations
Token Rotation
The CLOUDFLARE_TUNNEL_TOKEN does not automatically expire. Best practices for production deployments:
- Periodic rotation : Rotate tokens on a scheduled basis (e.g., quarterly)
- Incident response : Immediately rotate if token exposure is suspected
- Access logging : Monitor Cloudflare logs for tunnel usage patterns
Secret Storage in Production
The .env file approach is suitable for development but should be replaced in production:
| Environment | Recommended Secret Storage | Rationale |
|---|---|---|
| Development | .env file (local) | Simple, adequate for local testing |
| Production (single host) | Docker secrets, HashiCorp Vault | Encrypted at rest, access logging |
| Production (orchestrated) | Kubernetes secrets, AWS Secrets Manager | Integrated with orchestration platform |
Container Image Security
Both containers use official images from trusted registries:
eclipse-mosquitto:latest- Official Eclipse Foundation imagecloudflare/cloudflared:latest- Official Cloudflare image
Recommendation : Pin specific image versions rather than using latest to ensure reproducible deployments and controlled updates:
Sources : docker-compose.yml:3-4 docker-compose.yml:11-12
Threat Model Summary
Mitigated Threats
| Threat | Mitigation | Effectiveness |
|---|---|---|
| Network reconnaissance | No exposed ports | Complete - port scanning reveals nothing |
| Direct exploitation of Mosquitto | Traffic filtered through Cloudflare | High - reduces exploit surface |
| DDoS against origin | Cloudflare absorbs attack | Very High - Cloudflare’s network capacity |
| Man-in-the-middle | End-to-end TLS encryption | High - certificate validation required |
| Credential leakage via Git | .gitignore exclusion | High - if properly configured |
Residual Risks
| Risk | Severity | Mitigation Strategy |
|---|---|---|
| Token compromise | High | Token rotation, access monitoring, secrets management |
| Anonymous MQTT access | Medium-High | Enable authentication, implement ACLs (see Protected Branch) |
| Cloudflare service dependency | Medium | Accept as operational requirement, or implement alternative tunnel |
| Container escape | Low | Use updated Docker versions, implement AppArmor/SELinux profiles |
Insider threat (access to .env) | Medium | Implement principle of least privilege, audit file access |
Defense-in-Depth Layers
The system implements multiple independent security layers. An attacker must bypass all layers to compromise the system:
- Layer 1 - Cloudflare Edge : DDoS protection, rate limiting, WAF rules
- Layer 2 - Tunnel Authentication : Valid tunnel token required
- Layer 3 - Network Isolation : No direct route to containers from external networks
- Layer 4 - Application Security : Mosquitto’s internal security (minimal in default config)
- Layer 5 - Secret Management :
.gitignoreprevents token leakage through version control
Sources : .gitignore:1-2 README.md82 Diagram 1 (High-Level System Architecture), Diagram 6 (Data and Secret Flow)
Dismiss
Refresh this wiki
Enter email to refresh