Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GitHub

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:

PrincipleImplementationBenefit
Zero Trust Network AccessCloudflare Tunnel with outbound-only connectionsOrigin server has no exposed attack surface
Separation of Code and Secrets.gitignore exclusion of .env filePrevents credential leakage through version control
Defense in DepthMultiple 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 TypeTraditional DeploymentTunnel Deployment
Port ScanningVulnerable - ports 1883 and 9001 discoverableImmune - no listening ports on public internet
Direct DDoSVulnerable - origin server is attack targetProtected - Cloudflare absorbs attack
SSL/TLS Certificate ManagementRequired - operator manages certificatesUnnecessary - Cloudflare manages certificates
IP-based Access ControlFragile - IP addresses change, easily spoofedN/A - origin has no public IP exposure
Zero-day Exploits in MosquittoHigh impact - direct exploitationReduced 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 LayerImplementationFile Reference
Explicit exclusion.gitignore contains .env.gitignore1
Template file.env.sample shows format without secrets.env.sample1
DocumentationREADME instructs users to create .env manuallyREADME.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

BoundaryTrust LevelEntry RequirementsEnforcement Mechanism
Public Internet → Cloudflare EdgeUntrusted → TrustedTLS handshake, valid hostnameCloudflare network infrastructure
Cloudflare Edge → Tunnel InfrastructureTrusted → TrustedValid tunnel configurationCloudflare internal routing
Tunnel Infrastructure → cloudflared containerTrusted → TrustedCLOUDFLARE_TUNNEL_TOKEN authenticationTunnel protocol cryptographic verification
cloudflared container → mosquitto containerTrusted → TrustedDocker internal DNS resolutionDocker bridge network isolation
External clients → mosquitto containerForbiddenN/A - no direct route existsDocker 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:

  1. The Mosquitto broker is not accessible via the host’s network interfaces
  2. Port scanning of the host reveals no MQTT services
  3. Firewall rules on the host are irrelevant to MQTT access
  4. 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 FeatureDefault ConfigurationSecurity BenefitOperational Complexity
Anonymous accessEnabledNone - reduces securityLow - no credential management
Password authenticationDisabledWould prevent unauthorized accessMedium - requires credential distribution
Topic-level ACLsNot configuredWould limit topic access per clientHigh - requires ACL file management
TLS client certificatesNot configuredWould provide mutual TLS authenticationVery High - PKI infrastructure required

Enhanced Security Branch

The repository includes an alternate configuration branch (protected-no-wildcard) that implements:

  1. Topic-based Access Control : ACL file restricts wildcard subscriptions and enforces username-based topic prefixes
  2. Encrypted Retained Messages : Uses gocryptfs to encrypt persistent message storage
  3. 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 SegmentEncryption StatusJustification
Client → Cloudflare EdgeEncrypted (TLS 1.3)Public internet traversal requires encryption
Cloudflare Edge → Tunnel InfrastructureEncrypted (Cloudflare proprietary)Cloudflare’s internal network, encrypted by default
Tunnel Infrastructure → cloudflaredEncrypted (Tunnel protocol)Traverses internet between Cloudflare PoP and origin
cloudflaredmosquittoUnencrypted (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:

  1. Periodic rotation : Rotate tokens on a scheduled basis (e.g., quarterly)
  2. Incident response : Immediately rotate if token exposure is suspected
  3. 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:

EnvironmentRecommended Secret StorageRationale
Development.env file (local)Simple, adequate for local testing
Production (single host)Docker secrets, HashiCorp VaultEncrypted at rest, access logging
Production (orchestrated)Kubernetes secrets, AWS Secrets ManagerIntegrated with orchestration platform

Container Image Security

Both containers use official images from trusted registries:

  • eclipse-mosquitto:latest - Official Eclipse Foundation image
  • cloudflare/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

ThreatMitigationEffectiveness
Network reconnaissanceNo exposed portsComplete - port scanning reveals nothing
Direct exploitation of MosquittoTraffic filtered through CloudflareHigh - reduces exploit surface
DDoS against originCloudflare absorbs attackVery High - Cloudflare’s network capacity
Man-in-the-middleEnd-to-end TLS encryptionHigh - certificate validation required
Credential leakage via Git.gitignore exclusionHigh - if properly configured

Residual Risks

RiskSeverityMitigation Strategy
Token compromiseHighToken rotation, access monitoring, secrets management
Anonymous MQTT accessMedium-HighEnable authentication, implement ACLs (see Protected Branch)
Cloudflare service dependencyMediumAccept as operational requirement, or implement alternative tunnel
Container escapeLowUse updated Docker versions, implement AppArmor/SELinux profiles
Insider threat (access to .env)MediumImplement 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:

  1. Layer 1 - Cloudflare Edge : DDoS protection, rate limiting, WAF rules
  2. Layer 2 - Tunnel Authentication : Valid tunnel token required
  3. Layer 3 - Network Isolation : No direct route to containers from external networks
  4. Layer 4 - Application Security : Mosquitto’s internal security (minimal in default config)
  5. Layer 5 - Secret Management : .gitignore prevents 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