diff --git a/.github/workflows/deploy-cloud.yaml b/.github/workflows/deploy-cloud.yaml index 94e8387..36372d4 100644 --- a/.github/workflows/deploy-cloud.yaml +++ b/.github/workflows/deploy-cloud.yaml @@ -99,6 +99,11 @@ jobs: sed -i "s|__CUBE_PUBLIC_URL__|${{ secrets.CUBE_PUBLIC_URL }}|g" docker/.env sed -i "s|__CUBE_INTERNAL_AGENT_URL__|${{ secrets.CUBE_INTERNAL_AGENT_URL }}|g" docker/.env + # Replace Google OAuth placeholders + sed -i "s|__SMQ_GOOGLE_CLIENT_ID__|${{ secrets.SMQ_GOOGLE_CLIENT_ID }}|g" docker/.env + sed -i "s|__SMQ_GOOGLE_CLIENT_SECRET__|${{ secrets.SMQ_GOOGLE_CLIENT_SECRET }}|g" docker/.env + sed -i "s|__SMQ_GOOGLE_STATE__|${{ secrets.SMQ_GOOGLE_STATE }}|g" docker/.env + # Replace Traefik configuration placeholders sed -i "s|__TRAEFIK_HTTP_PORT__|${{ secrets.TRAEFIK_HTTP_PORT }}|g" docker/.env sed -i "s|__TRAEFIK_HTTPS_PORT__|${{ secrets.TRAEFIK_HTTPS_PORT }}|g" docker/.env @@ -111,10 +116,10 @@ jobs: docker compose -f docker/compose.yaml --profile cloud pull 2>&1 echo "Stopping existing services" - make down-cloud 2>&1 + docker compose -f docker/compose.yaml --profile cloud down 2>&1 echo "Starting cloud services" - make up-cloud 2>&1 + docker compose -f docker/compose.yaml --profile cloud up -d 2>&1 echo "Waiting for services to start (30 seconds)..." sleep 30 diff --git a/Makefile b/Makefile index 6f2a5b7..cee5842 100644 --- a/Makefile +++ b/Makefile @@ -155,8 +155,18 @@ up-vllm: config-vllm @echo "Starting Cube with vLLM backend..." docker compose -f docker/compose.yaml --profile vllm up -d +.PHONY: disable-atls +disable-atls: + @echo "Disabling attested TLS for local development..." + @sed -i 's|^UV_CUBE_AGENT_CLIENT_CERT=.*|UV_CUBE_AGENT_CLIENT_CERT=|' docker/.env + @sed -i 's|^UV_CUBE_AGENT_CLIENT_KEY=.*|UV_CUBE_AGENT_CLIENT_KEY=|' docker/.env + @sed -i 's|^UV_CUBE_AGENT_SERVER_CA_CERTS=.*|UV_CUBE_AGENT_SERVER_CA_CERTS=|' docker/.env + @sed -i 's|^UV_CUBE_AGENT_ATTESTED_TLS=.*|UV_CUBE_AGENT_ATTESTED_TLS=false|' docker/.env + @sed -i 's|^UV_CUBE_AGENT_ATTESTATION_POLICY=.*|UV_CUBE_AGENT_ATTESTATION_POLICY=|' docker/.env + @echo "✓ Attested TLS disabled" + .PHONY: up -up: enable-guardrails config-backend config-cloud-local +up: config-local enable-guardrails config-backend disable-atls ifeq ($(AI_BACKEND),vllm) @$(MAKE) up-vllm else @@ -164,19 +174,17 @@ else endif .PHONY: up-disable-guardrails -up-disable-guardrails: disable-guardrails config-backend config-cloud-local +up-disable-guardrails: config-cloud-local disable-guardrails config-backend disable-atls ifeq ($(AI_BACKEND),vllm) @$(MAKE) up-vllm else @$(MAKE) up-ollama endif -.PHONY: config-cloud-local -config-cloud-local: - @echo "Configuring cloud deployment for local environment..." - @cp docker/.env docker/.env.backup 2>/dev/null || true - @cp docker/traefik/dynamic.toml docker/traefik/dynamic.toml.backup 2>/dev/null || true - @cp docker/config.json docker/config.json.backup 2>/dev/null || true +.PHONY: config-local +config-local: + @echo "Configuring for local development..." + @git checkout -- docker/.env docker/traefik/dynamic.toml docker/config.json 2>/dev/null || true @sed -i 's|__SMQ_EMAIL_HOST__|localhost|g' docker/.env @sed -i 's|__SMQ_EMAIL_PORT__|1025|g' docker/.env @sed -i 's|__SMQ_EMAIL_USERNAME__|test|g' docker/.env @@ -189,67 +197,27 @@ config-cloud-local: @sed -i 's|__SMQ_GOOGLE_CLIENT_SECRET__||g' docker/.env @sed -i 's|__SMQ_GOOGLE_STATE__||g' docker/.env @sed -i 's|__CUBE_PUBLIC_URL__|localhost|g' docker/.env - @sed -i 's|^TRAEFIK_HTTP_PORT=.*|TRAEFIK_HTTP_PORT=49210|g' docker/.env - @sed -i 's|^TRAEFIK_HTTPS_PORT=.*|TRAEFIK_HTTPS_PORT=49211|g' docker/.env - @sed -i 's|^TRAEFIK_DASHBOARD_PORT=.*|TRAEFIK_DASHBOARD_PORT=49212|g' docker/.env + @sed -i 's|^TRAEFIK_HTTP_PORT=.*|TRAEFIK_HTTP_PORT=80|g' docker/.env + @sed -i 's|^TRAEFIK_HTTPS_PORT=.*|TRAEFIK_HTTPS_PORT=443|g' docker/.env + @sed -i 's|^TRAEFIK_DASHBOARD_PORT=.*|TRAEFIK_DASHBOARD_PORT=8080|g' docker/.env @echo "✓ Configured with local defaults" -.PHONY: restore-cloud-config -restore-cloud-config: - @echo "Restoring cloud deployment placeholders..." - @if [ -f docker/.env.backup ]; then \ - mv docker/.env.backup docker/.env; \ - echo "✓ Restored .env"; \ - fi - @if [ -f docker/traefik/dynamic.toml.backup ]; then \ - mv docker/traefik/dynamic.toml.backup docker/traefik/dynamic.toml; \ - echo "✓ Restored dynamic.toml"; \ - fi - @if [ -f docker/config.json.backup ]; then \ - mv docker/config.json.backup docker/config.json; \ - echo "✓ Restored config.json"; \ - fi - -.PHONY: up-cloud -up-cloud: config-cloud-local - @echo "Starting Cube Cloud services with local configuration..." - @mkdir -p docker/traefik/ssl/certs docker/traefik/letsencrypt - @if [ ! -f docker/traefik/ssl/certs/acme.json ]; then \ - printf '{}' > docker/traefik/ssl/certs/acme.json; \ - chmod 600 docker/traefik/ssl/certs/acme.json; \ - echo "✓ Created acme.json"; \ - fi - docker compose -f docker/compose.yaml --profile cloud up -d - @echo "" - @echo "=== Cube Cloud Services Started ===" - @echo " - UI: http://localhost:49210/" - @echo " - Proxy API: http://localhost:49210/proxy" - @echo " - Traefik Dashboard: http://localhost:49212" - @echo "" - @echo "Note: Run 'make restore-cloud-config' to restore placeholders after stopping" +.PHONY: restore-config +restore-config: + @echo "Restoring configuration placeholders..." + @git checkout -- docker/.env docker/traefik/dynamic.toml docker/config.json 2>/dev/null && \ + echo "✓ Restored from git" || echo "⚠ git restore failed, files may not be tracked" .PHONY: down down: @echo "Stopping all Cube services..." docker compose -f docker/compose.yaml down -.PHONY: down-cloud -down-cloud: - @echo "Stopping Cube Cloud services..." - docker compose -f docker/compose.yaml --profile cloud down - @$(MAKE) restore-cloud-config - .PHONY: down-volumes down-volumes: @echo "Stopping all Cube services and removing volumes..." docker compose -f docker/compose.yaml down -v -.PHONY: down-cloud-volumes -down-cloud-volumes: - @echo "Stopping Cube Cloud services and removing volumes..." - docker compose -f docker/compose.yaml --profile cloud down -v - @$(MAKE) restore-cloud-config - .PHONY: restart restart: down up @@ -259,9 +227,6 @@ restart-ollama: down up-ollama .PHONY: restart-vllm restart-vllm: down up-vllm -.PHONY: restart-cloud -restart-cloud: down-cloud up-cloud - .PHONY: logs logs: docker compose -f docker/compose.yaml logs -f @@ -345,7 +310,7 @@ help: @echo "" @echo "Cloud Configuration Commands:" @echo " config-cloud-local Configure cloud deployment with localhost defaults" - @echo " restore-cloud-config Restore placeholder values in cloud config files" + @echo " restore-config Restore placeholder values in config files" @echo "" @echo "Logs:" @echo " logs Show all logs" diff --git a/README.md b/README.md index 879afc1..5b74976 100644 --- a/README.md +++ b/README.md @@ -84,16 +84,17 @@ Cube AI uses TEEs to protect user data and AI models from unauthorized access. T # Local development with vLLM make up-vllm - # Cloud deployment (configures traefik for cloud ports) - make up-cloud - # Stop services make down - # Stop services and remove volumes + # Stop services and remove volumes (includes all profiles) make down-volumes ``` + **Local Development Access:** + - Traefik Gateway: https://localhost (ports 80/443) + - All services accessible through Traefik reverse proxy + 3. **Get your authentication token** All API requests require JWT authentication. Once services are running, obtain a token: @@ -188,9 +189,16 @@ Cube AI uses TEEs to protect user data and AI models from unauthorized access. T Cube AI exposes all services through a Traefik reverse proxy. All protected endpoints require the `Authorization: Bearer ` header with a valid JWT token. +**Local Development Access:** +- Via Traefik HTTPS: `https://localhost` (port 443) + +**Cloud Deployment Access:** +- Via Traefik HTTPS: `https://your-domain.com` + ### Proxy Endpoints (OpenAI-Compatible) -**Base URL:** `https://localhost/proxy/` +**Base URL (Local):** `https://localhost/proxy/` +**Base URL (Cloud):** `https://your-domain.com/proxy/` Replace `{domainID}` with your domain ID from the Getting Started section. @@ -231,7 +239,8 @@ curl -k https://localhost/proxy/YOUR_DOMAIN_ID/api/tags \ ### Auth Endpoints -**Base URL:** `https://localhost/users` +**Base URL (Local):** `https://localhost/users` +**Base URL (Cloud):** `https://your-domain.com/users` | Method | Path | Description | |--------|-------------------------------|----------------------------------------| @@ -254,7 +263,8 @@ curl -ksSiX POST https://localhost/users/tokens/issue \ ### Domains Endpoints -**Base URL:** `https://localhost/domains` +**Base URL (Local):** `https://localhost/domains` +**Base URL (Cloud):** `https://your-domain.com/domains` | Method | Path | Description | |--------|-------------------------------|----------------------------------------| diff --git a/docker/.env b/docker/.env index 0740a29..a392d9a 100644 --- a/docker/.env +++ b/docker/.env @@ -52,6 +52,7 @@ SMQ_AUTH_SECRET_KEY="ZA4vBf79fy6mrvQD2XnMqc4vNB9WDz" SMQ_AUTH_ACCESS_TOKEN_DURATION="1h" SMQ_AUTH_REFRESH_TOKEN_DURATION="24h" SMQ_AUTH_INVITATION_DURATION="168h" +SMQ_AUTH_LOGIN_TOKEN_DURATION= SMQ_AUTH_ADAPTER_INSTANCE_ID= SMQ_AUTH_URL=http://auth:8189 SMQ_AUTH_KEYS_ALGORITHM="EdDSA" @@ -248,6 +249,7 @@ UV_CUBE_UI_LLM_DEFAULT_MODEL=tinyllama:1.1b # UI Attestation Configuration CUBE_AI_ATTESTATION_URL=http://cube-proxy:${UV_CUBE_PROXY_PORT} +CUBE_AI_PROXY_URL=http://cube-proxy:${UV_CUBE_PROXY_PORT} ## Guardrails DB UV_GUARDRAILS_DB_HOST=cube-guardrails-db diff --git a/docker/supermq-compose.yaml b/docker/supermq-compose.yaml index 5527111..7359ea5 100644 --- a/docker/supermq-compose.yaml +++ b/docker/supermq-compose.yaml @@ -424,22 +424,6 @@ services: SMQ_AUTH_GRPC_CLIENT_CERT: ${SMQ_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} SMQ_AUTH_GRPC_CLIENT_KEY: ${SMQ_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} SMQ_AUTH_GRPC_SERVER_CA_CERTS: ${SMQ_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} - SMQ_GROUPS_GRPC_URL: ${SMQ_GROUPS_GRPC_URL} - SMQ_GROUPS_GRPC_TIMEOUT: ${SMQ_GROUPS_GRPC_TIMEOUT} - SMQ_GROUPS_GRPC_CLIENT_CERT: ${SMQ_GROUPS_GRPC_CLIENT_CERT:+/groups-grpc-client.crt} - SMQ_GROUPS_GRPC_CLIENT_KEY: ${SMQ_GROUPS_GRPC_CLIENT_KEY:+/groups-grpc-client.key} - SMQ_GROUPS_GRPC_SERVER_CA_CERTS: ${SMQ_GROUPS_GRPC_SERVER_CA_CERTS:+/groups-grpc-server-ca.crt} - SMQ_CHANNELS_URL: ${SMQ_CHANNELS_URL} - SMQ_CHANNELS_GRPC_URL: ${SMQ_CHANNELS_GRPC_URL} - SMQ_CHANNELS_GRPC_TIMEOUT: ${SMQ_CHANNELS_GRPC_TIMEOUT} - SMQ_CHANNELS_GRPC_CLIENT_CERT: ${SMQ_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} - SMQ_CHANNELS_GRPC_CLIENT_KEY: ${SMQ_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} - SMQ_CHANNELS_GRPC_SERVER_CA_CERTS: ${SMQ_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} - SMQ_CLIENTS_GRPC_URL: ${SMQ_CLIENTS_GRPC_URL} - SMQ_CLIENTS_GRPC_TIMEOUT: ${SMQ_CLIENTS_GRPC_TIMEOUT} - SMQ_CLIENTS_GRPC_CLIENT_CERT: ${SMQ_CLIENTS_GRPC_CLIENT_CERT:+/clients-grpc-client.crt} - SMQ_CLIENTS_GRPC_CLIENT_KEY: ${SMQ_CLIENTS_GRPC_CLIENT_KEY:+/clients-grpc-client.key} - SMQ_CLIENTS_GRPC_R_CA_CERTS: ${SMQ_CLIENTS_GRPC_SERVER_CA_CERTS:+/clients-grpc-server-ca.crt} SMQ_AUTH_KEYS_ALGORITHM: ${SMQ_AUTH_KEYS_ALGORITHM} SMQ_AUTH_JWKS_URL: ${SMQ_AUTH_JWKS_URL} SMQ_JAEGER_URL: ${SMQ_JAEGER_URL}