Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict users to their own messages & auto-persist w/ encrypted storage #3

Merged
merged 15 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test-mosquitto:
Expand All @@ -16,27 +12,50 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up Docker Compose
- name: Set up Docker and Docker Compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose

- name: Start Mosquitto service using Docker Compose
run: docker-compose up -d mosquitto

- name: Wait for Mosquitto to be healthy
- name: Wait for Mosquitto to be healthy and publish message
run: |
for i in {1..10}; do
if docker inspect --format='{{.State.Status}}' mosquitto | grep -q running; then
echo "Mosquitto is running"
exit 0
for i in {1..20}; do
STATUS=$(docker inspect --format='{{.State.Health.Status}}' mosquitto)
echo "Current Mosquitto health status: $STATUS"
if [ "$STATUS" = "healthy" ]; then
echo "Mosquitto is healthy"
if docker exec mosquitto mosquitto_pub -t test/topic -m "Test message" -r; then
echo "Message published successfully"
exit 0
else
echo "Failed to publish message, retrying..."
sleep 10
fi
else
echo "Waiting for Mosquitto to be healthy..."
sleep 10
fi
done

echo "Mosquitto did not become healthy in time"
docker logs mosquitto
exit 1

- name: Stop Mosquitto service using Docker Compose
run: docker-compose down
- name: Stop Mosquitto service and capture logs
run: |
docker-compose logs mosquitto
docker-compose down

- name: Check encrypted data
run: |
docker run --rm -v $(pwd)/data:/encrypted alpine:latest /bin/sh -c '
if [ -f /encrypted/gocryptfs.conf ] && [ -f /encrypted/gocryptfs.diriv ]; then
echo "Encrypted volume configuration files found";
else
echo "Encrypted volume configuration files not found";
exit 1;
fi
'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.env
data/*
22 changes: 20 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,29 @@ version: '3.8'

services:
mosquitto:
image: eclipse-mosquitto:latest
build: ./mosquitto
container_name: mosquitto
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./mosquitto/aclfile:/mosquitto/config/aclfile
- ./data:/encrypted
restart: unless-stopped
entrypoint: /entrypoint.sh
cap_add:
- SYS_ADMIN
security_opt:
- apparmor:unconfined
devices:
- /dev/fuse
healthcheck:
test: ["CMD", "mosquitto_pub", "-t", "health", "-m", "health check"]
interval: 10s
timeout: 5s
retries: 10
environment:
# TODO: Adjust as neeed (but not here!)
GOCRYPT_PASSWORD: your_secure_password_here


cloudflared:
image: cloudflare/cloudflared:latest
Expand Down
5 changes: 0 additions & 5 deletions mosquitto.conf

This file was deleted.

35 changes: 35 additions & 0 deletions mosquitto/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Start with an Alpine base image
FROM alpine:latest

# Install necessary packages including FUSE, Mosquitto, and gocryptfs
RUN apk update && \
apk add --no-cache \
bash \
fuse \
gocryptfs \
mosquitto \
mosquitto-clients \
shadow

# Create necessary directories and set permissions
RUN mkdir -p /encrypted /var/lib/mosquitto && \
chown -R mosquitto:mosquitto /var/lib/mosquitto /encrypted && \
chmod -R 700 /var/lib/mosquitto && \
chmod -R 700 /encrypted

# Ensure mosquitto user has a valid shell
RUN usermod -s /bin/bash mosquitto

# Copy the Mosquitto configuration files and entrypoint script
COPY mosquitto.conf /mosquitto/config/mosquitto.conf
COPY aclfile /mosquitto/config/aclfile
COPY entrypoint.sh /entrypoint.sh

# Ensure entrypoint script is executable
RUN chmod +x /entrypoint.sh

# Expose Mosquitto ports
EXPOSE 1883 9001

# Set entrypoint
ENTRYPOINT ["/entrypoint.sh"]
2 changes: 2 additions & 0 deletions mosquitto/aclfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Only allow messages to be read and written within topics that match the username
pattern readwrite %u/#
Comment on lines +1 to +2
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what restricts users to their own messages. It is used in combination with the acl_file /mosquitto/config/aclfile entry in mosquitto/mosquitto.conf.

37 changes: 37 additions & 0 deletions mosquitto/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

set -e

# Ensure GOCRYPT_PASSWORD is set
if [ -z "$GOCRYPT_PASSWORD" ]; then
echo "GOCRYPT_PASSWORD is not set. Exiting."
exit 1
fi

# Create /var/lib/mosquitto directory if not exists
mkdir -p /var/lib/mosquitto

# Adjust permissions for the mosquitto user
chown mosquitto:mosquitto /var/lib/mosquitto /encrypted

# Initialize or mount the encrypted filesystem as the mosquitto user
su mosquitto -c "
if [ ! -f /encrypted/gocryptfs.conf ]; then
echo \"Initializing encrypted filesystem\"
if [ \"\$(ls -A /encrypted)\" ]; then
echo \"Error: /encrypted directory is not empty. Cannot initialize.\"
exit 1
fi
echo \"$GOCRYPT_PASSWORD\" | gocryptfs -init /encrypted
fi

echo \"Mounting encrypted filesystem\"
echo \"$GOCRYPT_PASSWORD\" | gocryptfs /encrypted /var/lib/mosquitto

# Debug: Check if gocryptfs is mounted
echo \"Checking if gocryptfs is mounted:\"
mount | grep gocryptfs || echo \"gocryptfs is not mounted\"
"

# Run Mosquitto as the mosquitto user
exec su mosquitto -c "mosquitto -c /mosquitto/config/mosquitto.conf"
26 changes: 26 additions & 0 deletions mosquitto/mosquitto.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
listener 1883
allow_anonymous true

listener 9001
protocol websockets

# Debug logging
# log_type all

acl_file /mosquitto/config/aclfile

# Enable persistent storage
persistence true

# Set the location for the persistence files
persistence_location /var/lib/mosquitto

# `mosquitto.db` is the default
# persistence_file mosquitto.db

# If configured with `autosave_on_changes` represents, this represents the total
# number of changes before an autosave. Otherwise, it uses seconds, and defaults
# to 1800 (30 minutes).
autosave_interval 1

autosave_on_changes true
Loading