131 lines
4.4 KiB
Python
131 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Hämta Cibello-prod-hemligheter från AWS SSM och skriv /opt/cibello-platform/.env.
|
|
|
|
SSM är enda sanningskällan. Kör detta vid varje deploy INNAN applikationen startas om.
|
|
Inga värden loggas. set +x aktiveras automatiskt.
|
|
"""
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REGION = os.environ.get("AWS_REGION", "eu-north-1")
|
|
SSM_PREFIX = "/cibello/prod"
|
|
ENV_PATH = Path(os.environ.get("ENV_PATH", "/opt/cibello-platform/.env"))
|
|
|
|
# Icke-hemliga värden som ändå behöver styras centralt.
|
|
# Dessa kan med fördel också flyttas till SSM (String/SecureString) senare.
|
|
STATIC_CONFIG = {
|
|
"NODE_ENV": "production",
|
|
"API_PORT": "4000",
|
|
"ADMIN_PORT": "5173",
|
|
"API_BASE_URL": "https://api.cibello.app",
|
|
"VITE_API_BASE_URL": "https://api.cibello.app",
|
|
"CORS_ORIGINS": "https://cibello.app,https://admin.cibello.app,https://api.cibello.app",
|
|
"REDIS_URL": "redis://localhost:6379",
|
|
"LOG_LEVEL": "info",
|
|
"AAMOS_MODE": "gemini",
|
|
"AAMOS_API_URL": "https://amos.aamos.systems",
|
|
"AAMOS_TIMEOUT_MS": "60000",
|
|
"GEMINI_MODEL": "gemini-2.5-flash",
|
|
"GEMINI_TIMEOUT_MS": "60000",
|
|
"GEMINI_DAILY_BUDGET_USD": "25",
|
|
"ENTITLEMENT_TTL_HOURS": "24",
|
|
"ENTITLEMENT_GRACE_DAYS": "7",
|
|
"JWT_ACCESS_TTL_SECONDS": "900",
|
|
"JWT_REFRESH_TTL_SECONDS": "2592000",
|
|
"S3_MODE": "aws",
|
|
"S3_BUCKET": "cibello-production",
|
|
"S3_REGION": "eu-north-1",
|
|
"SMTP_PORT": "587",
|
|
"SMTP_SECURE": "false",
|
|
"EMAIL_MODE": "log",
|
|
"EXPO_PUSH_ENABLED": "false",
|
|
"DATABASE_CA_CERT": "/opt/cibello-platform/certs/rds-global-bundle.pem",
|
|
}
|
|
|
|
# SSM-parameter → env-var. Värden från SSM skriver över STATIC_CONFIG om de krockar.
|
|
SSM_MAP = {
|
|
"aamos-api-key": "AAMOS_API_KEY",
|
|
"db-password": "DB_PASSWORD", # används för att bygga DATABASE_URL
|
|
"entitlement-signing-secret": "ENTITLEMENT_SIGNING_SECRET",
|
|
"eoc-push-token": "EOC_PUSH_TOKEN",
|
|
"gemini-api-key": "GEMINI_API_KEY",
|
|
"jwt-access-secret": "JWT_ACCESS_SECRET",
|
|
"jwt-refresh-secret": "JWT_REFRESH_SECRET",
|
|
"smtp-pass": "SMTP_PASS",
|
|
"ops-token": "OPS_TOKEN",
|
|
# Följande är valfria just nu men bör ligga i SSM
|
|
"google-service-account-json": "GOOGLE_SERVICE_ACCOUNT_JSON",
|
|
}
|
|
|
|
|
|
def get_parameters(names: list[str]) -> dict[str, str]:
|
|
if not names:
|
|
return {}
|
|
cmd = [
|
|
"aws", "ssm", "get-parameters",
|
|
"--names", *names,
|
|
"--with-decryption",
|
|
"--region", REGION,
|
|
]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
data = json.loads(result.stdout)
|
|
out = {}
|
|
for p in data.get("Parameters", []):
|
|
out[p["Name"]] = p["Value"]
|
|
for inv in data.get("InvalidParameters", []):
|
|
print(f"[sync-env] WARN: SSM-parameter saknas: {inv}", file=sys.stderr)
|
|
return out
|
|
|
|
|
|
def build_env(ssm: dict[str, str]) -> dict[str, str]:
|
|
env = dict(STATIC_CONFIG)
|
|
|
|
for short, var in SSM_MAP.items():
|
|
val = ssm.get(f"{SSM_PREFIX}/{short}")
|
|
if val is not None:
|
|
env[var] = val
|
|
|
|
db_password = env.get("DB_PASSWORD", "")
|
|
db_host = os.environ.get("DB_HOST", "cibello-prod-db.cvi0qcksmsfj.eu-north-1.rds.amazonaws.com")
|
|
db_name = os.environ.get("DB_NAME", "cibello")
|
|
test_db_name = os.environ.get("TEST_DB_NAME", "cibello_test")
|
|
db_user = os.environ.get("DB_USER", "cibello_admin")
|
|
db_sslmode = os.environ.get("DB_SSLMODE", "require")
|
|
|
|
if db_password:
|
|
env["DATABASE_URL"] = f"postgres://{db_user}:{db_password}@{db_host}:5432/{db_name}?sslmode={db_sslmode}"
|
|
env["TEST_DATABASE_URL"] = f"postgres://{db_user}:{db_password}@{db_host}:5432/{test_db_name}?sslmode={db_sslmode}"
|
|
|
|
# Rensa temporär nyckel
|
|
env.pop("DB_PASSWORD", None)
|
|
|
|
return env
|
|
|
|
|
|
def write_env(env: dict[str, str], dry_run: bool = False) -> None:
|
|
lines = [f"{k}={v}" for k, v in env.items()]
|
|
if dry_run:
|
|
print(f"[sync-env] DRY-RUN: skulle skriva {ENV_PATH} ({len(env)} rader)")
|
|
return
|
|
ENV_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
ENV_PATH.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
os.chmod(ENV_PATH, 0o600)
|
|
print(f"[sync-env] skrev {ENV_PATH} ({len(env)} rader)")
|
|
|
|
|
|
def main() -> int:
|
|
dry_run = "--dry-run" in sys.argv
|
|
names = [f"{SSM_PREFIX}/{short}" for short in SSM_MAP]
|
|
ssm = get_parameters(names)
|
|
env = build_env(ssm)
|
|
write_env(env, dry_run=dry_run)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|