feat: wire rswag backend to pull secrets from Infisical at startup
Add Python-based entrypoint.sh that authenticates with Infisical via universal-auth, fetches secrets, and exports them as env vars before starting uvicorn. Secrets like MOLLIE_API_KEY, PRODIGI_API_KEY, PRINTFUL_API_TOKEN, JWT_SECRET, GEMINI_API_KEY, and FLOW_* vars are now pulled from Infisical instead of being passed through docker-compose. Gracefully degrades: if no INFISICAL_CLIENT_ID/SECRET are set or if the fetch fails, the container starts with whatever env vars exist. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d8a58f8eb4
commit
b35df552f7
|
|
@ -36,6 +36,10 @@ COPY --chown=appuser:appgroup app/ ./app/
|
|||
COPY --chown=appuser:appgroup alembic/ ./alembic/
|
||||
COPY --chown=appuser:appgroup alembic.ini ./
|
||||
|
||||
# Copy Infisical entrypoint
|
||||
COPY --chown=appuser:appgroup entrypoint.sh ./entrypoint.sh
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
# Create directories for mounted volumes
|
||||
RUN mkdir -p /app/designs /app/config && \
|
||||
chown -R appuser:appgroup /app
|
||||
|
|
@ -44,4 +48,5 @@ USER appuser
|
|||
|
||||
EXPOSE 8000
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/sh
|
||||
# Infisical secret injection entrypoint (Python version)
|
||||
set -e
|
||||
|
||||
INFISICAL_URL="${INFISICAL_URL:-http://infisical:8080}"
|
||||
INFISICAL_ENV="${INFISICAL_ENV:-prod}"
|
||||
INFISICAL_PROJECT_SLUG="${INFISICAL_PROJECT_SLUG:-rswag}"
|
||||
|
||||
if [ -z "$INFISICAL_CLIENT_ID" ] || [ -z "$INFISICAL_CLIENT_SECRET" ]; then
|
||||
echo "[infisical] No credentials set, starting without secret injection"
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
echo "[infisical] Fetching secrets from ${INFISICAL_PROJECT_SLUG}/${INFISICAL_ENV}..."
|
||||
|
||||
EXPORTS=$(python3 -c "
|
||||
import urllib.request, json, os, sys
|
||||
|
||||
base = os.environ['INFISICAL_URL']
|
||||
slug = os.environ['INFISICAL_PROJECT_SLUG']
|
||||
env = os.environ['INFISICAL_ENV']
|
||||
|
||||
try:
|
||||
data = json.dumps({'clientId': os.environ['INFISICAL_CLIENT_ID'], 'clientSecret': os.environ['INFISICAL_CLIENT_SECRET']}).encode()
|
||||
req = urllib.request.Request(f'{base}/api/v1/auth/universal-auth/login', data=data, headers={'Content-Type': 'application/json'})
|
||||
auth = json.loads(urllib.request.urlopen(req).read())
|
||||
token = auth.get('accessToken')
|
||||
if not token:
|
||||
print('[infisical] Auth failed', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
req = urllib.request.Request(f'{base}/api/v3/secrets/raw?workspaceSlug={slug}&environment={env}&secretPath=/&recursive=true')
|
||||
req.add_header('Authorization', f'Bearer {token}')
|
||||
secrets = json.loads(urllib.request.urlopen(req).read())
|
||||
|
||||
if 'secrets' not in secrets:
|
||||
print('[infisical] No secrets returned', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
for s in secrets['secrets']:
|
||||
key = s['secretKey']
|
||||
val = s['secretValue'].replace(\"'\", \"'\\\\'\")
|
||||
print(f\"export {key}='{val}'\")
|
||||
except Exception as e:
|
||||
print(f'[infisical] Error: {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
" 2>&1) || {
|
||||
echo "[infisical] WARNING: Failed to fetch secrets, starting with existing env vars"
|
||||
exec "$@"
|
||||
}
|
||||
|
||||
if echo "$EXPORTS" | grep -q "^export "; then
|
||||
COUNT=$(echo "$EXPORTS" | grep -c "^export ")
|
||||
eval "$EXPORTS"
|
||||
echo "[infisical] Injected ${COUNT} secrets"
|
||||
else
|
||||
echo "[infisical] WARNING: $EXPORTS"
|
||||
echo "[infisical] Starting with existing env vars"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
|
@ -36,22 +36,16 @@ services:
|
|||
container_name: rswag-backend
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- INFISICAL_CLIENT_ID=${INFISICAL_CLIENT_ID}
|
||||
- INFISICAL_CLIENT_SECRET=${INFISICAL_CLIENT_SECRET}
|
||||
- INFISICAL_PROJECT_SLUG=rswag
|
||||
- INFISICAL_ENV=prod
|
||||
- INFISICAL_URL=http://infisical:8080
|
||||
- DATABASE_URL=postgresql://rswag:${DB_PASSWORD:-devpassword}@db:5432/rswag
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MOLLIE_API_KEY=${MOLLIE_API_KEY}
|
||||
- PRODIGI_API_KEY=${PRODIGI_API_KEY}
|
||||
- PRINTFUL_API_TOKEN=${PRINTFUL_API_TOKEN}
|
||||
- POD_SANDBOX_MODE=${POD_SANDBOX_MODE:-true}
|
||||
- JWT_SECRET=${JWT_SECRET:-dev-secret-change-me}
|
||||
- CORS_ORIGINS=${CORS_ORIGINS:-http://localhost:3000}
|
||||
- DESIGNS_PATH=/app/designs
|
||||
- CONFIG_PATH=/app/config
|
||||
- SPACES_PATH=/app/spaces
|
||||
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||
- FLOW_SERVICE_URL=${FLOW_SERVICE_URL:-}
|
||||
- FLOW_ID=${FLOW_ID:-}
|
||||
- FLOW_FUNNEL_ID=${FLOW_FUNNEL_ID:-}
|
||||
- FLOW_REVENUE_SPLIT=${FLOW_REVENUE_SPLIT:-0.5}
|
||||
volumes:
|
||||
- ./designs:/app/designs
|
||||
- ./config:/app/config:ro
|
||||
|
|
|
|||
Loading…
Reference in New Issue