diff --git a/.docker/compose/docker-compose.e2e.yml b/.docker/compose/docker-compose.e2e.yml index bea99b2a..5d8373b7 100644 --- a/.docker/compose/docker-compose.e2e.yml +++ b/.docker/compose/docker-compose.e2e.yml @@ -20,9 +20,9 @@ services: - CHARON_ENV=development - CHARON_DEBUG=0 - TZ=UTC - # E2E testing encryption key - 32 bytes base64 encoded (not for production!) - # Generated with: openssl rand -base64 32 - - CHARON_ENCRYPTION_KEY=ucDWy5ScLubd3QwCHhQa2SY7wL2OF48p/c9nZhyW1mA= + # Encryption key - MUST be provided via environment variable + # Generate with: export CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32) + - CHARON_ENCRYPTION_KEY=${CHARON_ENCRYPTION_KEY:?CHARON_ENCRYPTION_KEY is required} - CHARON_HTTP_PORT=8080 - CHARON_DB_PATH=/app/data/charon.db - CHARON_FRONTEND_DIR=/app/frontend/dist diff --git a/.docker/compose/docker-compose.playwright.yml b/.docker/compose/docker-compose.playwright.yml index 85f53526..4ca3d2e1 100644 --- a/.docker/compose/docker-compose.playwright.yml +++ b/.docker/compose/docker-compose.playwright.yml @@ -37,8 +37,9 @@ services: - CHARON_DEBUG=0 - TZ=UTC # E2E testing encryption key - 32 bytes base64 encoded (not for production!) - # Generated with: openssl rand -base64 32 - - CHARON_ENCRYPTION_KEY=ucDWy5ScLubd3QwCHhQa2SY7wL2OF48p/c9nZhyW1mA= + # Encryption key - MUST be provided via environment variable + # Generate with: export CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32) + - CHARON_ENCRYPTION_KEY=${CHARON_ENCRYPTION_KEY:?CHARON_ENCRYPTION_KEY is required} # Server settings - CHARON_HTTP_PORT=8080 - CHARON_DB_PATH=/app/data/charon.db diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index b4fb05bc..c7c4441d 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -163,6 +163,13 @@ jobs: docker load -i charon-e2e-image.tar docker images | grep charon + - name: Generate ephemeral encryption key + run: | + # Generate a unique, ephemeral encryption key for this CI run + # Key is 32 bytes, base64-encoded as required by CHARON_ENCRYPTION_KEY + echo "CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32)" >> $GITHUB_ENV + echo "✅ Generated ephemeral encryption key for E2E tests" + - name: Start test environment run: | # Use the committed docker-compose.playwright.yml for E2E testing diff --git a/docs/plans/current_spec.md b/docs/plans/current_spec.md new file mode 100644 index 00000000..962634cd --- /dev/null +++ b/docs/plans/current_spec.md @@ -0,0 +1,46 @@ +# Security Fix: Remove Hardcoded Encryption Keys from Docker Compose Files + +**Plan ID**: SEC-2026-001 +**Status**: ✅ IMPLEMENTED +**Priority**: Critical (Security) +**Created**: 2026-01-25 +**Implemented By**: Management Agent + +--- + +## Summary + +Removed hardcoded encryption keys from Docker Compose test files and implemented ephemeral key generation in CI workflows. + +## Changes Applied + +| File | Change | +|------|--------| +| `.docker/compose/docker-compose.playwright.yml` | Replaced hardcoded key with `${CHARON_ENCRYPTION_KEY:?...}` | +| `.docker/compose/docker-compose.e2e.yml` | Replaced hardcoded key with `${CHARON_ENCRYPTION_KEY:?...}` | +| `.github/workflows/e2e-tests.yml` | Added ephemeral key generation step | +| `.env.test.example` | Added prominent documentation | + +## Security Notes + +- The old key `ucDWy5ScLubd3QwCHhQa2SY7wL2OF48p/c9nZhyW1mA=` exists in git history +- This key should **NEVER** be used in any production environment +- Each CI run now generates a unique ephemeral key + +## Testing + +```bash +# Verify compose fails without key +unset CHARON_ENCRYPTION_KEY +docker compose -f .docker/compose/docker-compose.playwright.yml config 2>&1 +# Expected: "CHARON_ENCRYPTION_KEY is required" + +# Verify compose succeeds with key +export CHARON_ENCRYPTION_KEY=$(openssl rand -base64 32) +docker compose -f .docker/compose/docker-compose.playwright.yml config +# Expected: Valid YAML output +``` + +## References + +- **OWASP**: [A02:2021 – Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/)