From 780e1a7f014d093c38e14a2d438798d30195fadb Mon Sep 17 00:00:00 2001 From: MoonDev Date: Thu, 5 Feb 2026 23:16:18 +0300 Subject: [PATCH] first commit --- .gitignore | 38 ++++++++++ Caddyfile | 30 ++++++++ Dockerfile | 63 +++++++++++++++++ README.md | 148 +++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 44 ++++++++++++ entrypoint.sh | 45 ++++++++++++ process-static-docker.sh | 35 +++++++++ 7 files changed, 403 insertions(+) create mode 100644 .gitignore create mode 100644 Caddyfile create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 entrypoint.sh create mode 100644 process-static-docker.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3fa91f --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Environment variables +.env +.env.local +.env.*.local + +# SQLite database files +/data/* +# TLS certificates (private keys!) +/certs/* + +# Docker volumes +caddy-data/ +caddy-config/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ + +# Build artifacts +/build/ +/dist/ +/target/ + +# Temporary files +*.tmp +*.temp +.cache/ diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..a2b880e --- /dev/null +++ b/Caddyfile @@ -0,0 +1,30 @@ +{ + auto_https off +} + +:80 { + redir https://{host}{uri} +} + +attestation.app:443 { + tls /etc/caddy/certs/attestation.app.crt /etc/caddy/certs/attestation.app.key + + # Disable HSTS + header Strict-Transport-Security "" + + # Serve static files (HTML, CSS, images, etc.) + root * /srv/static + file_server + + # Proxy API endpoints to the attestation server + reverse_proxy /api/* attestation:8080 + + # Proxy Auditor app endpoints + reverse_proxy /auditor/* attestation:8080 + + # Enable logging + log { + output stdout + format json + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2cd7a03 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,63 @@ +FROM eclipse-temurin:21-jdk-jammy AS builder + +WORKDIR /build + +RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* + +RUN git clone --depth 1 --recurse-submodules https://github.com/GrapheneOS/AttestationServer.git . + +# Patch the server to bind to 0.0.0.0 instead of localhost (::1) +# This is required for Docker networking to work +RUN sed -i 's/new InetSocketAddress("::1", 8080)/new InetSocketAddress("0.0.0.0", 8080)/' \ + src/main/java/app/attestation/server/AttestationServer.java + +# Optional: Patch the domain if you want to use a custom domain +# Uncomment and modify the following line for your domain: +# RUN sed -i 's/attestation.app/your-domain.com/g' \ +# src/main/java/app/attestation/server/AttestationServer.java + +RUN chmod +x gradlew && ./gradlew build -x test --no-daemon + +# Process static files (replace {{css|...}} and {{js|...}} templates with SRI hashes) +RUN apt-get update && apt-get install -y --no-install-recommends \ + openssl sed \ + && rm -rf /var/lib/apt/lists/* + +COPY process-static-docker.sh /tmp/process-static.sh +RUN chmod +x /tmp/process-static.sh && /tmp/process-static.sh + +# --- Runtime --- +FROM eclipse-temurin:21-jre-jammy + +RUN apt-get update && apt-get install -y \ + curl \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -r -s /bin/false -u 1000 attestation + +WORKDIR /app + +# Copy the custom sqlite4java native library from the submodule +# This is built with newer SQLite that supports STRICT tables +RUN mkdir -p /app/libs +COPY --from=builder /build/libs/sqlite4java-prebuilt/libsqlite4java-linux-amd64-1.0.392.so /app/libs/ + +# Copy all JARs from builder +COPY --from=builder /build/build/libs/*.jar ./libs/ + +# Copy processed static files +COPY --from=builder /build/static ./static-orig/ + +COPY entrypoint.sh . +RUN chmod +x /app/entrypoint.sh + +# Create directories and set permissions +# /data - for SQLite databases +# /srv/static - for sharing static files with caddy +RUN mkdir -p /data /srv/static && \ + chown -R attestation:attestation /app /data /srv/static + +EXPOSE 8080 + +# Run as root initially to fix permissions, entrypoint will drop privileges +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5d22e2 --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +# GrapheneOS AttestationServer Docker + +Dockerized deployment of [GrapheneOS AttestationServer](https://github.com/GrapheneOS/AttestationServer) for local attestation. + +## Overview + +This project provides a containerized setup for running your own GrapheneOS AttestationServer. It includes: + +- **AttestationServer** - The main Java application handling attestations +- **Caddy** - Reverse proxy with HTTPS support +- **SQLite** - Local database storage for attestation data + +## Prerequisites + +Before running the server, ensure you have: + +1. **Docker** and **Docker Compose** installed +2. **TLS certificates** for `attestation.app` domain in the `certs/` directory: + - `certs/attestation.app.crt` - Certificate file + - `certs/attestation.app.key` - Private key file +3. **DNS or hosts file configuration** to resolve `attestation.app` to your server + +## Pre-Launch Setup + +### 1. Prepare TLS Certificates + +Place your TLS certificates for `attestation.app` in the `certs/` directory: +- `certs/attestation.app.crt` - Certificate +- `certs/attestation.app.key` - Private key + +> **Note:** Certificate generation is up to you. You can use self-signed certificates for local testing or certificates from a trusted CA. + +### 2. Configure DNS or Hosts File + +The GrapheneOS Auditor app expects to connect to `attestation.app`. You must redirect this domain to your local server's IP address. + +#### Option A: Local Machine (hosts file) + +Edit your hosts file: + +**Linux/macOS:** +```bash +sudo nano /etc/hosts +``` + +**Windows:** +``` +C:\Windows\System32\drivers\etc\hosts +``` + +Add the following line (replace `192.168.1.100` with your server's IP): +``` +192.168.1.100 attestation.app +``` + +#### Option B: Network-wide (DNS) + +Configure your router or local DNS server (like Pi-hole or AdGuard) to resolve `attestation.app` to your server's IP address. + +#### Option C: Android Device (root required) + +If your Android device is rooted, edit `/system/etc/hosts`: +```bash +su +mount -o remount,rw /system +echo "192.168.1.100 attestation.app" >> /system/etc/hosts +mount -o remount,ro /system +``` + +**Important:** You must configure this on the Android device running the Auditor app, not just the server. + +### 3. Create Data Directory + +Ensure the data directory exists for persistent SQLite storage: + +```bash +mkdir -p data +``` + +## Running the Server + +### Build and Start + +```bash +docker-compose up -d --build +``` + +This will: +1. Build the AttestationServer from source +2. Start the attestation service on port 8080 (internal) +3. Start Caddy reverse proxy on ports 80 and 443 + +### Check Status + +```bash +docker-compose ps +docker-compose logs -f +``` + +### Stop the Server + +```bash +docker-compose down +``` + +### Stop and Remove All Data + +```bash +docker-compose down -v +rm -rf data/*.db data/*.db-* +``` + +## Usage + +1. Ensure your Android device has `attestation.app` pointing to your server IP +2. Install [GrapheneOS Auditor](https://github.com/GrapheneOS/Auditor) app on your Android device +3. Open the Auditor app +4. The app will connect to your local attestation server instead of the official one + + +## Directory Structure + +``` +. +├── certs/ # TLS certificates +│ ├── attestation.app.crt +│ └── attestation.app.key +├── data/ # SQLite databases (persistent) +│ ├── attestation.db +│ └── samples.db +├── Caddyfile # Caddy reverse proxy config +├── Dockerfile # AttestationServer build +├── docker-compose.yml # Service orchestration +├── entrypoint.sh # Container entrypoint +└── process-static-docker.sh # Static file processor +``` + + +## Security Considerations + +- Keep your private key (`certs/attestation.app.key`) secure and never commit it to version control +- The `.gitignore` file excludes sensitive files like certificates and databases +- This setup is intended for **local/private use only** +- For production deployment, use properly signed certificates from a trusted CA + +## License + +This Docker setup follows the same license as the upstream [GrapheneOS AttestationServer](https://github.com/GrapheneOS/AttestationServer). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2996e71 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + attestation: + build: . + container_name: attestation-server + restart: unless-stopped + volumes: + # Persist SQLite databases (attestation.db and samples.db) + - ./data:/data + # Share static files with caddy (attestation copies, caddy serves) + - static-files:/srv/static + networks: + - internal + expose: + - "8080" + + caddy: + image: caddy:2-alpine + container_name: attestation-caddy + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "443:443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - ./certs:/etc/caddy/certs:ro + - caddy-data:/data + - caddy-config:/config + # Mount static files from shared volume + - static-files:/srv/static:ro + depends_on: + - attestation + networks: + - internal + +volumes: + caddy-data: + caddy-config: + static-files: + +networks: + internal: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..8e2b3ac --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -e + +# Fix permissions on /data directory (runtime volume mount may have wrong ownership) +# This ensures the attestation user can write SQLite databases +if [ -d "/data" ]; then + chown -R attestation:attestation /data + chmod 755 /data +fi + +# Copy static files to shared volume (if mounted) +if [ -d "/srv/static" ]; then + echo "Copying static files to shared volume..." + cp -r /app/static-orig/* /srv/static/ + chown -R attestation:attestation /srv/static + echo "Static files copied." +fi + +# Set working directory to /data where SQLite databases will be stored +# The application creates attestation.db and samples.db in the working directory +cd /data + +JAR_FILE="/app/libs/attestation-server.jar" + +if [ ! -f "$JAR_FILE" ]; then + echo "ERROR: Main JAR not found at $JAR_FILE!" + echo "Available JARs:" + ls -la /app/libs/ + exit 1 +fi + +echo "Starting AttestationServer..." +echo "JAR: $JAR_FILE" +echo "Data directory: $(pwd)" +echo "Running as user: attestation (UID 1000)" + +# Run with the sqlite4java library path, dropping privileges to attestation user +# Use setpriv to drop privileges while preserving environment +exec setpriv --reuid=attestation --regid=attestation --clear-groups \ + java \ + -Xmx512m \ + -XX:+UseG1GC \ + -XX:+ExitOnOutOfMemoryError \ + -Djava.library.path=/app/libs \ + -jar "$JAR_FILE" diff --git a/process-static-docker.sh b/process-static-docker.sh new file mode 100644 index 0000000..dfd1a07 --- /dev/null +++ b/process-static-docker.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +mkdir -p static-tmp +cp -a static/* static-tmp/ + +declare -a replacements + +while IFS= read -r file; do + [ -f "$file" ] || continue + hash=$(sha256sum "$file" | head -c 8) + sri_hash=sha256-$(openssl dgst -sha256 -binary "$file" | openssl base64 -A) + dest="$(dirname "$file")/$hash.$(basename "$file")" + rel_path="${file#*/}" + dest_path="${dest#*/}" + + if [[ "$file" == *.css ]]; then + replacements+=("s@{{css|/$rel_path}}@@g") + elif [[ "$file" == *.js ]]; then + replacements+=("s@{{js|/$rel_path}}@@g") + fi + + mv "$file" "$dest" + replacements+=("s@{{integrity|/$rel_path}}@$sri_hash@g") + replacements+=("s@{{path|/$rel_path}}@/$dest_path@g") +done < <(find static-tmp -type f \( -name "*.css" -o -name "*.js" \)) + +while IFS= read -r htmlfile; do + for rep in "${replacements[@]}"; do + sed -i "$rep" "$htmlfile" + done +done < <(find static-tmp -type f -name "*.html") + +rm -rf static +mv static-tmp static