This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Protected Branch Features
Loading…
Protected Branch Features
Relevant source files
Purpose and Scope
This document describes the advanced security features available in the protected-no-wildcard branch of this repository. These features provide enhanced access control, message encryption, and persistence capabilities beyond the base configuration in the main branch.
The protected branch implements three key enhancements:
- ACL-based wildcard topic restrictions
- Encrypted storage for retained messages
- Automatic persistence of retained messages
For basic deployment and configuration information, see Getting Started. For general production deployment considerations, see Production Deployment Considerations.
Sources : README.md:7-13
Overview of the Protected Branch
The protected-no-wildcard branch provides an alternative deployment configuration that addresses specific security and privacy requirements for multi-tenant or privacy-sensitive MQTT deployments. Unlike the main branch which provides anonymous access and no encryption, the protected branch implements defense-in-depth security measures.
Branch Access
| Resource | Location |
|---|---|
| Protected Branch | [protected-no-wildcard branch](https://github.com/jzombie/docker-mqtt-mosquitto-cloudflare-tunnel/blob/59f1274c/protected-no-wildcard branch) |
| Diff from Main | [main…protected-no-wildcard comparison](https://github.com/jzombie/docker-mqtt-mosquitto-cloudflare-tunnel/blob/59f1274c/main…protected-no-wildcard comparison) |
| ACL File | mosquitto/aclfile (in protected branch) |
The protected branch maintains the same container architecture and Cloudflare Tunnel integration as the main branch, adding security layers within the Mosquitto container and its configuration.
Sources : README.md:7-13
Wildcard Restriction via ACL File
Access Control List Implementation
The protected branch implements topic-level access control using Mosquitto’s ACL (Access Control List) system. The ACL file enforces a topic namespace convention where the first level of each topic path represents a username, preventing users from subscribing to wildcard patterns that cross user boundaries.
Topic Namespace Convention
<username>/<application>/<device>/<metric>
In this pattern:
<username>is the first-level topic segment- Users can only access topics beginning with their own username
- Wildcard subscriptions like
#or+/+/+are restricted to prevent cross-user data access
flowchart TD
Client["MQTT Client"] -->|SUBSCRIBE user1/sensors/#| CloudflareTunnel["Cloudflare Tunnel"]
CloudflareTunnel -->|Forward to mosquitto:9001| Cloudflared["cloudflared Container"]
Cloudflared --> MosquittoListener["Mosquitto WebSocket Listener\nPort 9001"]
MosquittoListener --> ACLCheck{"ACL Permission Check"}
ACLCheck -->|Load Rules| ACLFile["mosquitto/aclfile"]
ACLFile -->|Pattern Matching| ACLCheck
ACLCheck -->|Allowed| TopicTree["Topic Subscription Tree"]
ACLCheck -->|Denied| RejectSub["SUBACK with Failure Code"]
TopicTree --> MessageRoute["Route Messages to Client"]
RejectSub --> Client
MessageRoute --> Client
Publisher["Publishing Client"] -->|PUBLISH user2/data| CloudflareTunnel
CloudflareTunnel --> Cloudflared
Cloudflared --> MosquittoListener
MosquittoListener --> ACLCheckPub{"ACL Publish Check"}
ACLCheckPub -->|Read aclfile| ACLFile
ACLCheckPub -->|Allowed| TopicTree
ACLCheckPub -->|Denied| RejectPub["PUBACK with Error"]
RejectPub --> Publisher
ACL Enforcement Flow
Diagram : ACL enforcement flow showing how the aclfile mediates access to topics based on username-prefixed patterns.
Sources : README.md9
Naive Implementation Characteristics
The README describes this ACL implementation as “naive” because it relies on a simple convention rather than cryptographic authentication:
| Characteristic | Implementation Detail |
|---|---|
| Authentication | Users are not cryptographically authenticated; ACL assumes username is provided correctly |
| Namespace Convention | First-level topic segment must match username |
| Wildcard Blocking | Prevents # and multi-level + patterns that span users |
| Trust Model | Assumes clients accurately identify themselves |
This approach provides separation of concerns and data isolation in scenarios where clients are trusted or authenticated through external mechanisms (e.g., Cloudflare Access policies, API tokens in headers).
Sources : README.md9
Encrypted Retained Messages with gocryptfs
flowchart TB
subgraph "Docker Host Filesystem"
EncryptedVol["Encrypted Volume\ngocryptfs ciphertext"]
end
subgraph "mosquitto Container"
GocryptfsMount["gocryptfs FUSE Mount"]
PlaintextView["Plaintext View\n/mosquitto/data"]
MosquittoProcess["Mosquitto Process"]
PersistenceDir["persistence_location\nConfiguration Directive"]
end
subgraph "Message Lifecycle"
RetainedMsg["Retained Message\nMQTT PUBLISH with retain=true"]
WriteOperation["Write to Persistence Store"]
ReadOperation["Read from Persistence Store"]
DecryptedMsg["Decrypted Message\nDelivered to Subscriber"]
end
EncryptedVol <-->|FUSE System Calls| GocryptfsMount
GocryptfsMount -->|Transparent Encryption| PlaintextView
PlaintextView <--> MosquittoProcess
MosquittoProcess -->|References| PersistenceDir
RetainedMsg --> MosquittoProcess
MosquittoProcess --> WriteOperation
WriteOperation -->|Plaintext Write| PlaintextView
PlaintextView -->|Encrypted on Disk| GocryptfsMount
GocryptfsMount -->|Decrypt on Read| PlaintextView
PlaintextView --> ReadOperation
ReadOperation --> MosquittoProcess
MosquittoProcess --> DecryptedMsg
Overview
The protected branch integrates gocryptfs to encrypt Mosquitto’s retained message store at rest. This prevents unauthorized access to message content if the underlying storage volume is compromised or accessed outside the container.
gocryptfs Integration Architecture
Diagram : gocryptfs provides transparent encryption/decryption between Mosquitto’s plaintext operations and the encrypted on-disk storage.
Sources : README.md10
Encryption Properties
| Property | Value |
|---|---|
| Encryption Type | Filesystem-level encryption via FUSE |
| Cipher | Determined by gocryptfs (typically AES-256-GCM) |
| Key Storage | Configured at gocryptfs mount initialization |
| Performance | FUSE overhead; transparent to Mosquitto |
| Scope | Only retained messages in persistence_location |
Data Flow: Publishing a Retained Message
Diagram : Sequence showing how a retained message is transparently encrypted during the persistence operation.
Sources : README.md:10-11
Auto-Save Retained Messages
Persistence Trigger Mechanism
The protected branch configures Mosquitto to automatically save retained messages to persistent storage after every message operation. This differs from the default behavior where Mosquitto may defer writes to optimize performance.
Configuration Directive
The auto-save behavior is controlled by the autosave_interval directive in mosquitto.conf:
autosave_interval 1
Setting autosave_interval to 1 instructs Mosquitto to write the in-memory retained message database to disk after every message change (publish or removal of a retained message).
Sources : README.md11
Auto-Save Behavior Comparison
| Configuration | Behavior | Use Case |
|---|---|---|
| Main Branch | Default interval (1800 seconds) | Standard deployments with container restart tolerance |
| Protected Branch | Interval of 1 second | Data-critical deployments requiring immediate persistence |
Auto-Save State Machine
Diagram : State machine showing auto-save behavior triggered after each retained message operation.
Sources : README.md11
Performance Implications
| Aspect | Impact |
|---|---|
| Disk I/O | Increased write operations on every retained message |
| Latency | Minimal impact on PUBACK latency (async write) |
| Durability | Near-zero data loss on container crash |
| Throughput | May limit sustained retained message publish rate |
flowchart LR
subgraph "Main Branch Architecture"
MainMosq["mosquitto Container\n- Standard config\n- Anonymous access\n- No encryption"]
MainCF["cloudflared Container\n- Standard tunnel"]
MainVol["Volume: ./mosquitto.conf"]
MainVol --> MainMosq
MainCF --> MainMosq
end
subgraph "Protected Branch Architecture"
ProtMosq["mosquitto Container\n- ACL enabled\n- autosave_interval=1\n- gocryptfs mount"]
ProtCF["cloudflared Container\n- Standard tunnel"]
ProtACL["Volume: ./mosquitto/aclfile"]
ProtConf["Volume: ./mosquitto.conf\n+ ACL directives"]
ProtCrypt["Encrypted Volume\ngocryptfs"]
ProtACL --> ProtMosq
ProtConf --> ProtMosq
ProtCrypt <--> ProtMosq
ProtCF --> ProtMosq
end
For deployments with high-frequency retained message updates, the default autosave_interval may provide better throughput at the cost of potential data loss during abnormal termination.
Architectural Comparison: Main vs Protected Branch
Container Architecture Differences
Diagram : Comparison of container architectures between main and protected branches, highlighting additional components in the protected configuration.
Sources : README.md:7-13
Feature Matrix
| Feature | Main Branch | Protected Branch |
|---|---|---|
| Access Control | Anonymous, unrestricted | ACL-based, username-scoped |
| Wildcard Subscriptions | Allowed globally | Restricted to user namespace |
| Retained Message Encryption | None | gocryptfs transparent encryption |
| Persistence Interval | Default (30 minutes) | Immediate (1 second) |
| Additional Files | None | mosquitto/aclfile |
| Container Complexity | Minimal | Moderate (gocryptfs setup) |
| Suitable For | Development, trusted networks | Multi-tenant, privacy-sensitive |
flowchart TD
subgraph "User Isolation"
User1["User: alice"]
User2["User: bob"]
User3["User: charlie"]
end
subgraph "Topic Namespace"
T1["alice/home/temperature"]
T2["alice/home/humidity"]
T3["bob/sensors/motion"]
T4["bob/sensors/light"]
T5["charlie/devices/status"]
end
subgraph "ACL Enforcement"
ACL["mosquitto/aclfile\npattern: topic readwrite alice/#\npattern: topic readwrite bob/#\npattern: topic readwrite charlie/#"]
end
User1 -->|Allowed| T1
User1 -->|Allowed| T2
User1 -.->|Denied| T3
User1 -.->|Denied| T4
User2 -->|Allowed| T3
User2 -->|Allowed| T4
User2 -.->|Denied| T1
User3 -->|Allowed| T5
User3 -.->|Denied| T1
ACL -.->|Enforces| User1
ACL -.->|Enforces| User2
ACL -.->|Enforces| User3
Use Cases for Protected Branch Features
Multi-Tenant Deployments
In scenarios where multiple users or applications share a single MQTT broker, the ACL-based wildcard restrictions prevent data leakage across tenant boundaries:
Diagram : ACL enforcement creating isolated topic namespaces for multiple users.
Privacy-Sensitive Applications
For deployments handling sensitive data (healthcare, financial, personal information), the gocryptfs encryption ensures that retained messages stored on disk cannot be read without the encryption key:
Use Case: Healthcare IoT
- Medical devices publish patient vitals as retained messages
- Disk snapshots or backups contain only encrypted ciphertext
- Compromise of storage volume does not expose patient data
- Encryption key is managed separately from storage
Data Integrity Critical Systems
The auto-save mechanism ensures minimal data loss in crash scenarios:
| Scenario | Main Branch Impact | Protected Branch Impact |
|---|---|---|
| Container crash | Up to 30 minutes of retained messages lost | Maximum 1 second of messages lost |
| System power loss | Up to 30 minutes of retained messages lost | Maximum 1 second of messages lost |
| Normal shutdown | All messages persisted | All messages persisted |
Migration Between Branches
Switching from Main to Protected
To adopt the protected branch features:
- Review ACL requirements : Determine if your topic structure follows username-prefixed convention
- Configure gocryptfs : Initialize encrypted volume and obtain encryption key
- Update docker-compose.yml : Modify to mount gocryptfs volume and ACL file
- Test ACL rules : Verify wildcard restrictions work as expected
- Backup unencrypted data : Retained messages in main branch are plaintext
Switching from Protected to Main
To revert to the simpler main branch configuration:
- Decrypt retained messages : Use gocryptfs to access plaintext before migration
- Export critical data : Publish non-retained messages if needed for recovery
- Remove ACL restrictions : Understand that all topics become globally accessible
- Switch branch : Check out main branch and restart containers
Sources : README.md13
Configuration Files in Protected Branch
Additional Files
The protected branch introduces files not present in main:
| File | Purpose | Location |
|---|---|---|
mosquitto/aclfile | ACL pattern definitions | Mounted as volume in mosquitto container |
Modified mosquitto.conf | References ACL file, sets autosave_interval=1 | Replaces main branch version |
| gocryptfs initialization scripts | Set up encrypted filesystem | Container initialization |
Modified Configuration Directives
Expected changes to mosquitto.conf in protected branch:
# ACL Configuration
acl_file /mosquitto/config/aclfile
# Persistence Configuration
autosave_interval 1
persistence true
persistence_location /mosquitto/data/
Sources : README.md:9-11
Security Considerations
Threat Model
The protected branch defends against specific threats:
| Threat | Mitigation |
|---|---|
| Cross-tenant data access | ACL wildcard restrictions |
| Disk volume compromise | gocryptfs encryption at rest |
| Data loss on crash | Auto-save immediate persistence |
| Unauthorized topic subscription | ACL pattern matching |
Limitations
The protected branch does NOT protect against:
- Man-in-the-middle attacks (handled by Cloudflare Tunnel TLS)
- Compromised MQTT clients (they can still access their own namespace)
- Memory-resident message inspection (encryption only at rest)
- DoS attacks from authenticated users
For comprehensive security, combine protected branch features with:
- Cloudflare Access policies (see Security Model)
- MQTT authentication plugins
- Rate limiting and message size restrictions
- Network-level monitoring
Sources : README.md9
Summary
The protected-no-wildcard branch extends the base Docker MQTT Mosquitto deployment with three integrated security features:
- ACL-based wildcard restrictions isolate user topics using username-prefixed patterns
- gocryptfs encryption protects retained messages at rest with transparent filesystem encryption
- Auto-save persistence minimizes data loss by writing retained messages after every operation
These features are particularly valuable for multi-tenant deployments, privacy-sensitive applications, and systems requiring high data durability. The trade-offs include increased container complexity, potential performance impact from frequent disk writes, and operational overhead of managing ACL files and encryption keys.
For standard single-tenant or development deployments, the main branch provides a simpler configuration with anonymous access and no encryption. For production deployments requiring enhanced security and isolation, the protected branch implements defense-in-depth measures while maintaining the same Cloudflare Tunnel integration and container orchestration model.
Sources : README.md:7-13
Dismiss
Refresh this wiki
Enter email to refresh