first commit
This commit is contained in:
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@@ -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/
|
||||
30
Caddyfile
Normal file
30
Caddyfile
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
63
Dockerfile
Normal file
63
Dockerfile
Normal file
@@ -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"]
|
||||
148
README.md
Normal file
148
README.md
Normal file
@@ -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).
|
||||
44
docker-compose.yml
Normal file
44
docker-compose.yml
Normal file
@@ -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:
|
||||
45
entrypoint.sh
Normal file
45
entrypoint.sh
Normal file
@@ -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"
|
||||
35
process-static-docker.sh
Normal file
35
process-static-docker.sh
Normal file
@@ -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}}@<link rel=\"stylesheet\" href=\"/$dest_path\" integrity=\"$sri_hash\"/>@g")
|
||||
elif [[ "$file" == *.js ]]; then
|
||||
replacements+=("s@{{js|/$rel_path}}@<script type=\"module\" src=\"/$dest_path\" integrity=\"$sri_hash\"></script>@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
|
||||
Reference in New Issue
Block a user