feat: wire rfiles to pull secrets from Infisical at startup
Add entrypoint.sh that authenticates with Infisical via universal auth and injects secrets as environment variables before the main process starts. Update Dockerfile with ENTRYPOINT directive and add Infisical connection vars to all services in both compose files (dev and prod). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
88674debd4
commit
28aafb73fe
|
|
@ -18,6 +18,9 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|||
|
||||
COPY . .
|
||||
|
||||
COPY entrypoint.sh /app/entrypoint.sh
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
RUN mkdir -p /app/staticfiles /app/media
|
||||
|
||||
EXPOSE 8000
|
||||
|
|
@ -25,4 +28,5 @@ EXPOSE 8000
|
|||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/api/health/ || exit 1
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
||||
|
|
|
|||
|
|
@ -58,14 +58,15 @@ services:
|
|||
- rfiles_media:/app/media
|
||||
- rfiles_static:/app/staticfiles
|
||||
environment:
|
||||
- INFISICAL_CLIENT_ID=${INFISICAL_CLIENT_ID}
|
||||
- INFISICAL_CLIENT_SECRET=${INFISICAL_CLIENT_SECRET}
|
||||
- INFISICAL_PROJECT_SLUG=rfiles
|
||||
- INFISICAL_ENV=prod
|
||||
- INFISICAL_URL=http://infisical:8080
|
||||
- DATABASE_URL=postgresql://rfiles:${DB_PASSWORD}@postgres:5432/rfiles
|
||||
- CELERY_BROKER_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- CELERY_RESULT_BACKEND=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- DJANGO_SETTINGS_MODULE=config.settings
|
||||
- DEBUG=False
|
||||
- ALLOWED_HOSTS=rfiles.online,www.rfiles.online,.rfiles.online,direct.rfiles.online,localhost
|
||||
- SHARE_BASE_URL=https://rfiles.online
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
@ -114,11 +115,15 @@ services:
|
|||
volumes:
|
||||
- rfiles_media:/app/media
|
||||
environment:
|
||||
- INFISICAL_CLIENT_ID=${INFISICAL_CLIENT_ID}
|
||||
- INFISICAL_CLIENT_SECRET=${INFISICAL_CLIENT_SECRET}
|
||||
- INFISICAL_PROJECT_SLUG=rfiles
|
||||
- INFISICAL_ENV=prod
|
||||
- INFISICAL_URL=http://infisical:8080
|
||||
- DATABASE_URL=postgresql://rfiles:${DB_PASSWORD}@postgres:5432/rfiles
|
||||
- CELERY_BROKER_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- CELERY_RESULT_BACKEND=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- DJANGO_SETTINGS_MODULE=config.settings
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
@ -148,11 +153,15 @@ services:
|
|||
container_name: rfiles-celery-beat
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- INFISICAL_CLIENT_ID=${INFISICAL_CLIENT_ID}
|
||||
- INFISICAL_CLIENT_SECRET=${INFISICAL_CLIENT_SECRET}
|
||||
- INFISICAL_PROJECT_SLUG=rfiles
|
||||
- INFISICAL_ENV=prod
|
||||
- INFISICAL_URL=http://infisical:8080
|
||||
- DATABASE_URL=postgresql://rfiles:${DB_PASSWORD}@postgres:5432/rfiles
|
||||
- CELERY_BROKER_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- CELERY_RESULT_BACKEND=redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
- DJANGO_SETTINGS_MODULE=config.settings
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
depends_on:
|
||||
- celery-worker
|
||||
healthcheck:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
#!/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:-rfiles}"
|
||||
|
||||
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:
|
||||
# Auth
|
||||
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)
|
||||
|
||||
# Fetch secrets
|
||||
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 "$@"
|
||||
Loading…
Reference in New Issue