feat: Add Docker secrets support for ResetData API key
This commit introduces secure Docker secrets integration for the ResetData
API key, enabling CHORUS to read sensitive configuration from mounted secret
files instead of environment variables.
## Key Changes:
**Security Enhancement:**
- Modified `pkg/config/config.go` to support reading ResetData API key from
Docker secret files using `getEnvOrFileContent()` pattern
- Enables secure deployment with `RESETDATA_API_KEY_FILE` pointing to
mounted secret file instead of plain text environment variables
**Container Deployment:**
- Added `Dockerfile.simple` for optimized Alpine-based deployment using
pre-built static binaries (chorus-agent)
- Updated `docker-compose.yml` with proper secret mounting configuration
- Fixed container binary path to use new `chorus-agent` instead of deprecated
`chorus` wrapper
**WHOOSH Integration:**
- Critical for WHOOSH wave-based auto-scaling system integration
- Enables secure credential management in Docker Swarm deployments
- Supports dynamic scaling operations while maintaining security standards
## Technical Details:
The ResetData configuration now supports both environment variable fallback
and Docker secrets:
```go
APIKey: getEnvOrFileContent("RESETDATA_API_KEY", "RESETDATA_API_KEY_FILE")
```
This change enables CHORUS to participate in WHOOSH's wave-based scaling
architecture while maintaining production-grade security for API credentials.
## Testing:
- Verified successful deployment in Docker Swarm environment
- Confirmed CHORUS agent initialization with secret-based configuration
- Validated integration with BACKBEAT and P2P networking components
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
42
Dockerfile.simple
Normal file
42
Dockerfile.simple
Normal file
@@ -0,0 +1,42 @@
|
||||
# CHORUS - Simple Docker image using pre-built binary
|
||||
FROM alpine:3.18
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apk --no-cache add \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
curl
|
||||
|
||||
# Create non-root user for security
|
||||
RUN addgroup -g 1000 chorus && \
|
||||
adduser -u 1000 -G chorus -s /bin/sh -D chorus
|
||||
|
||||
# Create application directories
|
||||
RUN mkdir -p /app/data && \
|
||||
chown -R chorus:chorus /app
|
||||
|
||||
# Copy pre-built binary
|
||||
COPY chorus-agent /app/chorus-agent
|
||||
RUN chmod +x /app/chorus-agent && chown chorus:chorus /app/chorus-agent
|
||||
|
||||
# Switch to non-root user
|
||||
USER chorus
|
||||
WORKDIR /app
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 8080 8081 9000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:8081/health || exit 1
|
||||
|
||||
# Set default environment variables
|
||||
ENV LOG_LEVEL=info \
|
||||
LOG_FORMAT=structured \
|
||||
CHORUS_BIND_ADDRESS=0.0.0.0 \
|
||||
CHORUS_API_PORT=8080 \
|
||||
CHORUS_HEALTH_PORT=8081 \
|
||||
CHORUS_P2P_PORT=9000
|
||||
|
||||
# Start CHORUS
|
||||
ENTRYPOINT ["/app/chorus-agent"]
|
||||
@@ -2,7 +2,7 @@ version: "3.9"
|
||||
|
||||
services:
|
||||
chorus:
|
||||
image: anthonyrawlins/chorus:backbeat-v2.0.1
|
||||
image: anthonyrawlins/chorus:resetdata-secrets-v1.0.5
|
||||
|
||||
# REQUIRED: License configuration (CHORUS will not start without this)
|
||||
environment:
|
||||
@@ -28,7 +28,7 @@ services:
|
||||
|
||||
# ResetData configuration (default provider)
|
||||
- RESETDATA_BASE_URL=${RESETDATA_BASE_URL:-https://models.au-syd.resetdata.ai/v1}
|
||||
- RESETDATA_API_KEY=${RESETDATA_API_KEY:?RESETDATA_API_KEY is required for resetdata provider}
|
||||
- RESETDATA_API_KEY_FILE=/run/secrets/resetdata_api_key
|
||||
- RESETDATA_MODEL=${RESETDATA_MODEL:-meta/llama-3.1-8b-instruct}
|
||||
|
||||
# Ollama configuration (alternative provider)
|
||||
@@ -56,12 +56,13 @@ services:
|
||||
# Docker secrets for sensitive configuration
|
||||
secrets:
|
||||
- chorus_license_id
|
||||
- resetdata_api_key
|
||||
|
||||
# Persistent data storage
|
||||
volumes:
|
||||
- chorus_data:/app/data
|
||||
# Mount prompts directory read-only for role YAMLs and defaults.md
|
||||
- ../prompts:/etc/chorus/prompts:ro
|
||||
- /rust/containers/WHOOSH/prompts:/etc/chorus/prompts:ro
|
||||
|
||||
# Network ports
|
||||
ports:
|
||||
@@ -91,6 +92,7 @@ services:
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname != rosewood
|
||||
- node.hostname != acacia
|
||||
preferences:
|
||||
- spread: node.hostname
|
||||
# CHORUS is internal-only, no Traefik labels needed
|
||||
@@ -120,7 +122,7 @@ services:
|
||||
start_period: 10s
|
||||
|
||||
whoosh:
|
||||
image: anthonyrawlins/whoosh:backbeat-v2.1.0
|
||||
image: anthonyrawlins/whoosh:scaling-v1.0.0
|
||||
ports:
|
||||
- target: 8080
|
||||
published: 8800
|
||||
@@ -163,6 +165,11 @@ services:
|
||||
WHOOSH_REDIS_PORT: 6379
|
||||
WHOOSH_REDIS_PASSWORD_FILE: /run/secrets/redis_password
|
||||
WHOOSH_REDIS_DATABASE: 0
|
||||
|
||||
# Scaling system configuration
|
||||
WHOOSH_SCALING_KACHING_URL: "https://kaching.chorus.services"
|
||||
WHOOSH_SCALING_BACKBEAT_URL: "http://backbeat-pulse:8080"
|
||||
WHOOSH_SCALING_CHORUS_URL: "http://chorus:8080"
|
||||
secrets:
|
||||
- whoosh_db_password
|
||||
- gitea_token
|
||||
@@ -170,6 +177,8 @@ services:
|
||||
- jwt_secret
|
||||
- service_tokens
|
||||
- redis_password
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
deploy:
|
||||
replicas: 2
|
||||
restart_policy:
|
||||
@@ -190,6 +199,8 @@ services:
|
||||
# monitor: 60s
|
||||
# order: stop-first
|
||||
placement:
|
||||
constraints:
|
||||
- node.hostname != acacia
|
||||
preferences:
|
||||
- spread: node.hostname
|
||||
resources:
|
||||
@@ -522,6 +533,9 @@ secrets:
|
||||
chorus_license_id:
|
||||
external: true
|
||||
name: chorus_license_id
|
||||
resetdata_api_key:
|
||||
external: true
|
||||
name: resetdata_api_key
|
||||
whoosh_db_password:
|
||||
external: true
|
||||
name: whoosh_db_password
|
||||
|
||||
@@ -179,7 +179,7 @@ func LoadFromEnvironment() (*Config, error) {
|
||||
},
|
||||
ResetData: ResetDataConfig{
|
||||
BaseURL: getEnvOrDefault("RESETDATA_BASE_URL", "https://models.au-syd.resetdata.ai/v1"),
|
||||
APIKey: os.Getenv("RESETDATA_API_KEY"),
|
||||
APIKey: getEnvOrFileContent("RESETDATA_API_KEY", "RESETDATA_API_KEY_FILE"),
|
||||
Model: getEnvOrDefault("RESETDATA_MODEL", "meta/llama-3.1-8b-instruct"),
|
||||
Timeout: getEnvDurationOrDefault("RESETDATA_TIMEOUT", 30*time.Second),
|
||||
},
|
||||
@@ -363,3 +363,17 @@ func SaveConfig(cfg *Config, configPath string) error {
|
||||
// For containers, configuration is environment-based, so this is a no-op
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadRuntimeConfig loads configuration with runtime assignment support
|
||||
func LoadRuntimeConfig() (*RuntimeConfig, error) {
|
||||
// Load base configuration from environment
|
||||
baseConfig, err := LoadFromEnvironment()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load base configuration: %w", err)
|
||||
}
|
||||
|
||||
// Create runtime configuration manager
|
||||
runtimeConfig := NewRuntimeConfig(baseConfig)
|
||||
|
||||
return runtimeConfig, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user