Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
96 changes: 93 additions & 3 deletions .github/workflows/release-traceway.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ on:
permissions:
contents: write
actions: write
packages: write
id-token: write

jobs:
release:
Expand Down Expand Up @@ -160,10 +162,98 @@ jobs:
gh workflow run release-website.yml --ref "${{ github.ref_name }}"
gh workflow run release-docs.yml --ref "${{ github.ref_name }}"

build-docker:
runs-on: ubuntu-latest
needs: release
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push full image
id: docker_build_full
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}
ghcr.io/${{ github.repository_owner }}/traceway:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push minimal image
id: docker_build_minimal
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.minimal
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}-minimal
ghcr.io/${{ github.repository_owner }}/traceway:minimal
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push SQLite image
id: docker_build_sqlite
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.sqlite
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}-sqlite
ghcr.io/${{ github.repository_owner }}/traceway:sqlite
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Install Cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.2.0'

- name: Sign full image
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign --yes ghcr.io/${{ github.repository_owner }}/traceway@${{ steps.docker_build_full.outputs.digest }}

- name: Sign minimal image
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign --yes ghcr.io/${{ github.repository_owner }}/traceway@${{ steps.docker_build_minimal.outputs.digest }}

- name: Sign SQLite image
env:
COSIGN_EXPERIMENTAL: 1
run: |
cosign sign --yes ghcr.io/${{ github.repository_owner }}/traceway@${{ steps.docker_build_sqlite.outputs.digest }}

- name: Summary
run: |
echo "Released backend/v${{ inputs.version }}" >> "$GITHUB_STEP_SUMMARY"
echo "### Docker Images (signed with Cosign)" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Full Image** (ClickHouse + PostgreSQL + supervisord):" >> "$GITHUB_STEP_SUMMARY"
echo "\`ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Minimal Image** (external ClickHouse/PostgreSQL):" >> "$GITHUB_STEP_SUMMARY"
echo "\`ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}-minimal\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**SQLite Image** (embedded SQLite, single binary, no dependencies):" >> "$GITHUB_STEP_SUMMARY"
echo "\`ghcr.io/${{ github.repository_owner }}/traceway:v${{ inputs.version }}-sqlite\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "Users can now: \`go get github.com/tracewayapp/traceway/backend@v${{ inputs.version }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "All images tagged with version, plus \`latest\`, \`minimal\`, and \`sqlite\` respectively." >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "Website and docs deploys will run automatically on release publish." >> "$GITHUB_STEP_SUMMARY"
echo "See [DOCKER_SIGNATURES.md](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/DOCKER_SIGNATURES.md) to verify image signatures." >> "$GITHUB_STEP_SUMMARY"
204 changes: 204 additions & 0 deletions DOCKER_SIGNATURES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Docker Image Signatures

All official Traceway Docker images are cryptographically signed using [Cosign](https://docs.sigstore.dev/cosign/overview/), a CNCF tool for container image signing and verification.

## Why Image Signatures Matter

Signed images provide:
- **Authenticity**: Verify the image comes from the official Traceway project
- **Integrity**: Ensure the image hasn't been modified or tampered with
- **Transparency**: Signatures are publicly verifiable using GitHub's OIDC token

## Available Images

Traceway publishes three Docker image variants to GitHub Container Registry (GHCR):

| Image | Purpose | Size | Best For |
|-------|---------|------|----------|
| `ghcr.io/tracewayapp/traceway:v*` | **Full** — ClickHouse + PostgreSQL + supervisord | ~600MB | Large deployments, multi-service setup |
| `ghcr.io/tracewayapp/traceway:v*-minimal` | **Minimal** — single binary with external databases | ~20-30MB | Kubernetes, scalable setups, external database infrastructure |
| `ghcr.io/tracewayapp/traceway:v*-sqlite` | **SQLite** — embedded SQLite, single binary, zero dependencies | ~50-80MB | Small VPS, testing, single-server deployments, embedded mode |

All images are cryptographically signed. Pull the latest release:

```bash
# Full image (all services included)
docker pull ghcr.io/tracewayapp/traceway:latest

# Minimal image (external databases)
docker pull ghcr.io/tracewayapp/traceway:minimal

# SQLite image (embedded, no external dependencies)
docker pull ghcr.io/tracewayapp/traceway:sqlite
```

## Verifying Signatures

### Install Cosign

**macOS:**
```bash
brew install cosign
```

**Linux:**
```bash
wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign
```

**Windows (PowerShell):**
```powershell
Invoke-WebRequest -Uri "https://github.com/sigstore/cosign/releases/latest/download/cosign-windows-amd64.exe" -OutFile cosign.exe
# Add cosign.exe to your PATH
```

### Verify Signature

```bash
# Full image
cosign verify \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
ghcr.io/tracewayapp/traceway:latest

# Minimal image
cosign verify \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
ghcr.io/tracewayapp/traceway:minimal

# SQLite image
cosign verify \
--certificate-identity-regexp '.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
ghcr.io/tracewayapp/traceway:sqlite
```

### Example Output

A successful verification looks like:
```
Verification successful!
```

If verification fails, the image may have been tampered with and should not be used.

## How Signatures Are Generated

1. **Build & Push**: GitHub Actions builds the Docker image and pushes it to GHCR
2. **Sign**: Cosign signs the image using GitHub's OIDC token (keyless signing)
3. **Store**: Signature is stored in GHCR alongside the image

## Using in Docker Compose

```yaml
version: '3.8'

services:
traceway:
image: ghcr.io/tracewayapp/traceway:latest
# Optionally verify the signature before running:
# Run: cosign verify ... ghcr.io/tracewayapp/traceway:latest
ports:
- "80:80"
- "8082:8082"
volumes:
- clickhouse_data:/var/lib/clickhouse
- postgres_data:/var/lib/postgresql/data
environment:
GIN_MODE: release

volumes:
clickhouse_data:
postgres_data:
```

## Minimal Image with External Databases

For scalable deployments with external ClickHouse/PostgreSQL:

```yaml
version: '3.8'

services:
traceway:
image: ghcr.io/tracewayapp/traceway:minimal
ports:
- "80:80"
- "8082:8082"
environment:
GIN_MODE: release
CLICKHOUSE_SERVER: clickhouse:9000
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
# ... other env vars

clickhouse:
image: clickhouse/clickhouse-server:latest
# ... configuration

postgres:
image: postgres:15
# ... configuration
```

## SQLite Image (Embedded, Zero Dependencies)

For small deployments, testing, or single-server setups:

```yaml
version: '3.8'

services:
traceway:
image: ghcr.io/tracewayapp/traceway:sqlite
ports:
- "80:80"
- "8082:8082"
volumes:
- traceway_data:/data
environment:
GIN_MODE: release

volumes:
traceway_data:
```

The SQLite image:
- Stores all data in `/data/traceway.db` (SQLite database)
- Stores blobs in `/data/storage` (if using local storage)
- Requires only one volume mount for all persistent state
- Perfect for VPS, small instances, or development

To persist data across restarts, mount a host folder or named volume at `/data`:

```bash
docker run -v /var/lib/traceway:/data ghcr.io/tracewayapp/traceway:sqlite
```

## Troubleshooting

**"Verification failed" error:**
- Ensure you're using the correct image URI (with version tag or `latest`)
- Check your internet connection (Cosign needs to fetch OIDC tokens)
- Try verifying a different version tag

**"cosign not found":**
- Ensure Cosign is installed and in your `$PATH`
- Run `cosign version` to verify installation

**"Certificate verification failed":**
- This indicates the image signature is invalid
- Do not use this image — report it to the Traceway team

## More Information

- [Cosign Documentation](https://docs.sigstore.dev/cosign/overview/)
- [Traceway Self-Hosting Guide](https://docs.tracewayapp.com/server)
- [SBOM (Software Bill of Materials)](https://docs.sigstore.dev/cosign/sbom/)

## Questions?

If you have questions about Docker image security or signatures, [open an issue](https://github.com/tracewayapp/traceway/issues) or ask in the [Traceway Discord](https://discord.gg/9tPn2SB3).
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ cd traceway && docker compose up -d

Point any OTel SDK at `http://localhost/api/otel/v1/traces` (or `/metrics`, `/logs`) and traces start flowing. See the [self-hosting docs](https://docs.tracewayapp.com/server/docker-compose) for production deployment, TLS, and storage configuration.

**Docker images are cryptographically signed.** See [DOCKER_SIGNATURES.md](./DOCKER_SIGNATURES.md) to verify images before deploying.

### Embedded mode (inside your Go app)

Run Traceway inside your Go process — no Docker, no external databases, SQLite under the hood:
Expand Down