refactor: merge vendor user into saas-admin
The admin user IS the platform admin — no separate vendor user needed. The saas-vendor role is now always assigned to the admin user during bootstrap. Removes VENDOR_ENABLED, VENDOR_USER, VENDOR_PASS from all config, prompts, compose templates, and bootstrap script. In multi-tenant mode: admin logs in with saas-admin credentials, gets platform:admin scope via saas-vendor role, manages tenants directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -77,9 +77,6 @@ services:
|
|||||||
PG_DB_SAAS: ${POSTGRES_DB:-cameleer_saas}
|
PG_DB_SAAS: ${POSTGRES_DB:-cameleer_saas}
|
||||||
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
||||||
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:-admin}
|
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:-admin}
|
||||||
VENDOR_SEED_ENABLED: "${VENDOR_SEED_ENABLED:-false}"
|
|
||||||
VENDOR_USER: ${VENDOR_USER:-vendor}
|
|
||||||
VENDOR_PASS: ${VENDOR_PASS:-vendor}
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3001/oidc/.well-known/openid-configuration', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\" && test -f /data/logto-bootstrap.json"]
|
test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3001/oidc/.well-known/openid-configuration', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\" && test -f /data/logto-bootstrap.json"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
|
|||||||
@@ -28,13 +28,7 @@ API_RESOURCE_NAME="Cameleer SaaS API"
|
|||||||
SAAS_ADMIN_USER="${SAAS_ADMIN_USER:-admin}"
|
SAAS_ADMIN_USER="${SAAS_ADMIN_USER:-admin}"
|
||||||
SAAS_ADMIN_PASS="${SAAS_ADMIN_PASS:-admin}"
|
SAAS_ADMIN_PASS="${SAAS_ADMIN_PASS:-admin}"
|
||||||
|
|
||||||
# Vendor seed (optional — creates saas-vendor role + vendor user)
|
# No server config — servers are provisioned dynamically by the admin console
|
||||||
VENDOR_SEED_ENABLED="${VENDOR_SEED_ENABLED:-false}"
|
|
||||||
VENDOR_USER="${VENDOR_USER:-vendor}"
|
|
||||||
VENDOR_PASS="${VENDOR_PASS:-vendor}"
|
|
||||||
VENDOR_NAME="${VENDOR_NAME:-SaaS Vendor}"
|
|
||||||
|
|
||||||
# No server config — servers are provisioned dynamically by the vendor console
|
|
||||||
|
|
||||||
# Redirect URIs (derived from PUBLIC_HOST and PUBLIC_PROTOCOL)
|
# Redirect URIs (derived from PUBLIC_HOST and PUBLIC_PROTOCOL)
|
||||||
HOST="${PUBLIC_HOST:-localhost}"
|
HOST="${PUBLIC_HOST:-localhost}"
|
||||||
@@ -92,7 +86,7 @@ for i in $(seq 1 60); do
|
|||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
# No server wait — servers are provisioned dynamically by the vendor console
|
# No server wait — servers are provisioned dynamically by the admin console
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# PHASE 2: Get Management API token
|
# PHASE 2: Get Management API token
|
||||||
@@ -345,8 +339,7 @@ fi
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
# --- Organization roles: owner, operator, viewer ---
|
# --- Organization roles: owner, operator, viewer ---
|
||||||
# Note: platform-admin / saas-vendor global role is NOT created here.
|
# Note: saas-vendor global role is created in Phase 12 and assigned to the admin user.
|
||||||
# It is injected via docker/vendor-seed.sh on the hosted SaaS environment only.
|
|
||||||
log "Creating organization roles..."
|
log "Creating organization roles..."
|
||||||
EXISTING_ORG_ROLES=$(api_get "/api/organization-roles")
|
EXISTING_ORG_ROLES=$(api_get "/api/organization-roles")
|
||||||
|
|
||||||
@@ -491,8 +484,8 @@ fi
|
|||||||
fi # end: ADMIN_TOKEN check
|
fi # end: ADMIN_TOKEN check
|
||||||
fi # end: M_ADMIN_SECRET check
|
fi # end: M_ADMIN_SECRET check
|
||||||
|
|
||||||
# No viewer user — tenant users are created by the vendor during tenant provisioning.
|
# No viewer user — tenant users are created by the admin during tenant provisioning.
|
||||||
# No example organization — tenants are created via the vendor console.
|
# No example organization — tenants are created via the admin console.
|
||||||
# No server OIDC config — each provisioned server gets OIDC from env vars.
|
# No server OIDC config — each provisioned server gets OIDC from env vars.
|
||||||
ORG_ID=""
|
ORG_ID=""
|
||||||
|
|
||||||
@@ -583,118 +576,44 @@ EOF
|
|||||||
chmod 644 "$BOOTSTRAP_FILE"
|
chmod 644 "$BOOTSTRAP_FILE"
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Phase 12: Vendor Seed (optional)
|
# Phase 12: SaaS Admin Role
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
if [ "$VENDOR_SEED_ENABLED" = "true" ]; then
|
log ""
|
||||||
log ""
|
log "=== Phase 12: SaaS Admin Role ==="
|
||||||
log "=== Phase 12a: Vendor Seed ==="
|
|
||||||
|
|
||||||
# Create saas-vendor global role with all API scopes
|
# Create saas-vendor global role with all API scopes
|
||||||
log "Checking for saas-vendor role..."
|
log "Checking for saas-vendor role..."
|
||||||
EXISTING_ROLES=$(api_get "/api/roles")
|
EXISTING_ROLES=$(api_get "/api/roles")
|
||||||
VENDOR_ROLE_ID=$(echo "$EXISTING_ROLES" | jq -r '.[] | select(.name == "saas-vendor" and .type == "User") | .id')
|
VENDOR_ROLE_ID=$(echo "$EXISTING_ROLES" | jq -r '.[] | select(.name == "saas-vendor" and .type == "User") | .id')
|
||||||
|
|
||||||
if [ -z "$VENDOR_ROLE_ID" ]; then
|
if [ -z "$VENDOR_ROLE_ID" ]; then
|
||||||
ALL_SCOPE_IDS=$(api_get "/api/resources/$API_RESOURCE_ID/scopes" | jq '[.[].id]')
|
ALL_SCOPE_IDS=$(api_get "/api/resources/$API_RESOURCE_ID/scopes" | jq '[.[].id]')
|
||||||
log "Creating saas-vendor role with all scopes..."
|
log "Creating saas-vendor role with all scopes..."
|
||||||
VENDOR_ROLE_RESPONSE=$(api_post "/api/roles" "{
|
VENDOR_ROLE_RESPONSE=$(api_post "/api/roles" "{
|
||||||
\"name\": \"saas-vendor\",
|
\"name\": \"saas-vendor\",
|
||||||
\"description\": \"SaaS vendor — full platform control across all tenants\",
|
\"description\": \"SaaS vendor — full platform control across all tenants\",
|
||||||
\"type\": \"User\",
|
\"type\": \"User\",
|
||||||
\"scopeIds\": $ALL_SCOPE_IDS
|
\"scopeIds\": $ALL_SCOPE_IDS
|
||||||
}")
|
}")
|
||||||
VENDOR_ROLE_ID=$(echo "$VENDOR_ROLE_RESPONSE" | jq -r '.id')
|
VENDOR_ROLE_ID=$(echo "$VENDOR_ROLE_RESPONSE" | jq -r '.id')
|
||||||
log "Created saas-vendor role: $VENDOR_ROLE_ID"
|
log "Created saas-vendor role: $VENDOR_ROLE_ID"
|
||||||
else
|
else
|
||||||
log "saas-vendor role exists: $VENDOR_ROLE_ID"
|
log "saas-vendor role exists: $VENDOR_ROLE_ID"
|
||||||
fi
|
|
||||||
|
|
||||||
# Assign vendor role to admin user
|
|
||||||
if [ -n "$VENDOR_ROLE_ID" ] && [ "$VENDOR_ROLE_ID" != "null" ] && [ -n "$ADMIN_USER_ID" ]; then
|
|
||||||
api_post "/api/users/$ADMIN_USER_ID/roles" "{\"roleIds\": [\"$VENDOR_ROLE_ID\"]}" >/dev/null 2>&1
|
|
||||||
log "Assigned saas-vendor role to admin user."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create separate vendor user if credentials provided
|
|
||||||
if [ -n "$VENDOR_USER" ] && [ "$VENDOR_USER" != "$SAAS_ADMIN_USER" ]; then
|
|
||||||
log "Checking for vendor user '$VENDOR_USER'..."
|
|
||||||
VENDOR_USER_ID=$(api_get "/api/users?search=$VENDOR_USER" | jq -r ".[] | select(.username == \"$VENDOR_USER\") | .id")
|
|
||||||
|
|
||||||
if [ -z "$VENDOR_USER_ID" ]; then
|
|
||||||
log "Creating vendor user '$VENDOR_USER'..."
|
|
||||||
VENDOR_RESPONSE=$(api_post "/api/users" "{
|
|
||||||
\"username\": \"$VENDOR_USER\",
|
|
||||||
\"password\": \"$VENDOR_PASS\",
|
|
||||||
\"name\": \"$VENDOR_NAME\"
|
|
||||||
}")
|
|
||||||
VENDOR_USER_ID=$(echo "$VENDOR_RESPONSE" | jq -r '.id')
|
|
||||||
log "Created vendor user: $VENDOR_USER_ID"
|
|
||||||
else
|
|
||||||
log "Vendor user exists: $VENDOR_USER_ID"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Assign saas-vendor role to vendor user
|
|
||||||
if [ -n "$VENDOR_ROLE_ID" ] && [ "$VENDOR_ROLE_ID" != "null" ]; then
|
|
||||||
api_post "/api/users/$VENDOR_USER_ID/roles" "{\"roleIds\": [\"$VENDOR_ROLE_ID\"]}" >/dev/null 2>&1
|
|
||||||
log "Assigned saas-vendor role to vendor user."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add vendor to all existing organizations with owner role
|
|
||||||
log "Adding vendor to all organizations..."
|
|
||||||
ORG_OWNER_ROLE_ID=$(api_get "/api/organization-roles" | jq -r '.[] | select(.name == "owner") | .id')
|
|
||||||
ORGS=$(api_get "/api/organizations")
|
|
||||||
ORG_COUNT=$(echo "$ORGS" | jq 'length')
|
|
||||||
|
|
||||||
for i in $(seq 0 $((ORG_COUNT - 1))); do
|
|
||||||
SEED_ORG_ID=$(echo "$ORGS" | jq -r ".[$i].id")
|
|
||||||
SEED_ORG_NAME=$(echo "$ORGS" | jq -r ".[$i].name")
|
|
||||||
api_post "/api/organizations/$SEED_ORG_ID/users" "{\"userIds\": [\"$VENDOR_USER_ID\"]}" >/dev/null 2>&1
|
|
||||||
if [ -n "$ORG_OWNER_ROLE_ID" ] && [ "$ORG_OWNER_ROLE_ID" != "null" ]; then
|
|
||||||
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" $HOST_ARGS \
|
|
||||||
-d "{\"organizationRoleIds\": [\"$ORG_OWNER_ROLE_ID\"]}" \
|
|
||||||
"${LOGTO_ENDPOINT}/api/organizations/$SEED_ORG_ID/users/$VENDOR_USER_ID/roles" >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
log " Added to org '$SEED_ORG_NAME' with owner role."
|
|
||||||
done
|
|
||||||
|
|
||||||
# Grant vendor user Logto console access
|
|
||||||
if [ -n "$ADMIN_TOKEN" ] && [ "$ADMIN_TOKEN" != "null" ]; then
|
|
||||||
log "Granting vendor Logto console access..."
|
|
||||||
VENDOR_CONSOLE_USER_ID=$(admin_api_get "/api/users?search=$VENDOR_USER" | jq -r ".[] | select(.username == \"$VENDOR_USER\") | .id" 2>/dev/null)
|
|
||||||
if [ -z "$VENDOR_CONSOLE_USER_ID" ] || [ "$VENDOR_CONSOLE_USER_ID" = "null" ]; then
|
|
||||||
VENDOR_CONSOLE_RESPONSE=$(admin_api_post "/api/users" "{
|
|
||||||
\"username\": \"$VENDOR_USER\",
|
|
||||||
\"password\": \"$VENDOR_PASS\",
|
|
||||||
\"name\": \"$VENDOR_NAME\"
|
|
||||||
}")
|
|
||||||
VENDOR_CONSOLE_USER_ID=$(echo "$VENDOR_CONSOLE_RESPONSE" | jq -r '.id')
|
|
||||||
log "Created vendor console user: $VENDOR_CONSOLE_USER_ID"
|
|
||||||
else
|
|
||||||
log "Vendor console user exists: $VENDOR_CONSOLE_USER_ID"
|
|
||||||
fi
|
|
||||||
if [ -n "$VENDOR_CONSOLE_USER_ID" ] && [ "$VENDOR_CONSOLE_USER_ID" != "null" ]; then
|
|
||||||
ADMIN_USER_ROLE_ID=$(admin_api_get "/api/roles" | jq -r '.[] | select(.name == "user") | .id')
|
|
||||||
ADMIN_ROLE_ID=$(admin_api_get "/api/roles" | jq -r '.[] | select(.name == "default:admin") | .id')
|
|
||||||
V_ROLE_IDS="[]"
|
|
||||||
[ -n "$ADMIN_USER_ROLE_ID" ] && [ "$ADMIN_USER_ROLE_ID" != "null" ] && V_ROLE_IDS=$(echo "$V_ROLE_IDS" | jq ". + [\"$ADMIN_USER_ROLE_ID\"]")
|
|
||||||
[ -n "$ADMIN_ROLE_ID" ] && [ "$ADMIN_ROLE_ID" != "null" ] && V_ROLE_IDS=$(echo "$V_ROLE_IDS" | jq ". + [\"$ADMIN_ROLE_ID\"]")
|
|
||||||
[ "$V_ROLE_IDS" != "[]" ] && admin_api_post "/api/users/$VENDOR_CONSOLE_USER_ID/roles" "{\"roleIds\": $V_ROLE_IDS}" >/dev/null 2>&1
|
|
||||||
log "Vendor granted Logto console access."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Vendor seed complete."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Assign vendor role to admin user
|
||||||
|
if [ -n "$VENDOR_ROLE_ID" ] && [ "$VENDOR_ROLE_ID" != "null" ] && [ -n "$ADMIN_USER_ID" ]; then
|
||||||
|
api_post "/api/users/$ADMIN_USER_ID/roles" "{\"roleIds\": [\"$VENDOR_ROLE_ID\"]}" >/dev/null 2>&1
|
||||||
|
log "Assigned saas-vendor role to admin user."
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "SaaS admin role configured."
|
||||||
|
|
||||||
log ""
|
log ""
|
||||||
log "=== Bootstrap complete! ==="
|
log "=== Bootstrap complete! ==="
|
||||||
# dev only — remove credential logging in production
|
# dev only — remove credential logging in production
|
||||||
log " SPA Client ID: $SPA_ID"
|
log " SPA Client ID: $SPA_ID"
|
||||||
if [ "$VENDOR_SEED_ENABLED" = "true" ]; then
|
|
||||||
log " Vendor: $VENDOR_USER / $VENDOR_PASS (role: saas-vendor)"
|
|
||||||
fi
|
|
||||||
log ""
|
log ""
|
||||||
log " No tenants created — use the vendor console to create tenants."
|
log " No tenants created — use the admin console to create tenants."
|
||||||
log ""
|
log ""
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ DEFAULT_HTTP_PORT="80"
|
|||||||
DEFAULT_HTTPS_PORT="443"
|
DEFAULT_HTTPS_PORT="443"
|
||||||
DEFAULT_LOGTO_CONSOLE_PORT="3002"
|
DEFAULT_LOGTO_CONSOLE_PORT="3002"
|
||||||
DEFAULT_LOGTO_CONSOLE_EXPOSED="true"
|
DEFAULT_LOGTO_CONSOLE_EXPOSED="true"
|
||||||
DEFAULT_VENDOR_ENABLED="false"
|
|
||||||
DEFAULT_VENDOR_USER="vendor"
|
|
||||||
DEFAULT_COMPOSE_PROJECT="cameleer-saas"
|
DEFAULT_COMPOSE_PROJECT="cameleer-saas"
|
||||||
DEFAULT_COMPOSE_PROJECT_STANDALONE="cameleer"
|
DEFAULT_COMPOSE_PROJECT_STANDALONE="cameleer"
|
||||||
DEFAULT_DOCKER_SOCKET="/var/run/docker.sock"
|
DEFAULT_DOCKER_SOCKET="/var/run/docker.sock"
|
||||||
@@ -42,9 +40,6 @@ _ENV_HTTP_PORT="${HTTP_PORT:-}"
|
|||||||
_ENV_HTTPS_PORT="${HTTPS_PORT:-}"
|
_ENV_HTTPS_PORT="${HTTPS_PORT:-}"
|
||||||
_ENV_LOGTO_CONSOLE_PORT="${LOGTO_CONSOLE_PORT:-}"
|
_ENV_LOGTO_CONSOLE_PORT="${LOGTO_CONSOLE_PORT:-}"
|
||||||
_ENV_LOGTO_CONSOLE_EXPOSED="${LOGTO_CONSOLE_EXPOSED:-}"
|
_ENV_LOGTO_CONSOLE_EXPOSED="${LOGTO_CONSOLE_EXPOSED:-}"
|
||||||
_ENV_VENDOR_ENABLED="${VENDOR_ENABLED:-}"
|
|
||||||
_ENV_VENDOR_USER="${VENDOR_USER:-}"
|
|
||||||
_ENV_VENDOR_PASS="${VENDOR_PASS:-}"
|
|
||||||
_ENV_MONITORING_NETWORK="${MONITORING_NETWORK:-}"
|
_ENV_MONITORING_NETWORK="${MONITORING_NETWORK:-}"
|
||||||
_ENV_COMPOSE_PROJECT="${COMPOSE_PROJECT:-}"
|
_ENV_COMPOSE_PROJECT="${COMPOSE_PROJECT:-}"
|
||||||
_ENV_DOCKER_SOCKET="${DOCKER_SOCKET:-}"
|
_ENV_DOCKER_SOCKET="${DOCKER_SOCKET:-}"
|
||||||
@@ -66,9 +61,6 @@ HTTP_PORT=""
|
|||||||
HTTPS_PORT=""
|
HTTPS_PORT=""
|
||||||
LOGTO_CONSOLE_PORT=""
|
LOGTO_CONSOLE_PORT=""
|
||||||
LOGTO_CONSOLE_EXPOSED=""
|
LOGTO_CONSOLE_EXPOSED=""
|
||||||
VENDOR_ENABLED=""
|
|
||||||
VENDOR_USER=""
|
|
||||||
VENDOR_PASS=""
|
|
||||||
MONITORING_NETWORK=""
|
MONITORING_NETWORK=""
|
||||||
VERSION=""
|
VERSION=""
|
||||||
COMPOSE_PROJECT=""
|
COMPOSE_PROJECT=""
|
||||||
@@ -169,9 +161,6 @@ parse_args() {
|
|||||||
--https-port) HTTPS_PORT="$2"; shift ;;
|
--https-port) HTTPS_PORT="$2"; shift ;;
|
||||||
--logto-console-port) LOGTO_CONSOLE_PORT="$2"; shift ;;
|
--logto-console-port) LOGTO_CONSOLE_PORT="$2"; shift ;;
|
||||||
--logto-console-exposed) LOGTO_CONSOLE_EXPOSED="$2"; shift ;;
|
--logto-console-exposed) LOGTO_CONSOLE_EXPOSED="$2"; shift ;;
|
||||||
--vendor-enabled) VENDOR_ENABLED="$2"; shift ;;
|
|
||||||
--vendor-user) VENDOR_USER="$2"; shift ;;
|
|
||||||
--vendor-password) VENDOR_PASS="$2"; shift ;;
|
|
||||||
--monitoring-network) MONITORING_NETWORK="$2"; shift ;;
|
--monitoring-network) MONITORING_NETWORK="$2"; shift ;;
|
||||||
--version) VERSION="$2"; shift ;;
|
--version) VERSION="$2"; shift ;;
|
||||||
--compose-project) COMPOSE_PROJECT="$2"; shift ;;
|
--compose-project) COMPOSE_PROJECT="$2"; shift ;;
|
||||||
@@ -219,7 +208,6 @@ show_help() {
|
|||||||
echo "Expert options:"
|
echo "Expert options:"
|
||||||
echo " --postgres-password, --clickhouse-password, --http-port,"
|
echo " --postgres-password, --clickhouse-password, --http-port,"
|
||||||
echo " --https-port, --logto-console-port, --logto-console-exposed,"
|
echo " --https-port, --logto-console-port, --logto-console-exposed,"
|
||||||
echo " --vendor-enabled, --vendor-user, --vendor-password,"
|
|
||||||
echo " --compose-project, --docker-socket, --node-tls-reject"
|
echo " --compose-project, --docker-socket, --node-tls-reject"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Re-run options:"
|
echo "Re-run options:"
|
||||||
@@ -256,9 +244,6 @@ load_config_file() {
|
|||||||
https_port) [ -z "$HTTPS_PORT" ] && HTTPS_PORT="$value" ;;
|
https_port) [ -z "$HTTPS_PORT" ] && HTTPS_PORT="$value" ;;
|
||||||
logto_console_port) [ -z "$LOGTO_CONSOLE_PORT" ] && LOGTO_CONSOLE_PORT="$value" ;;
|
logto_console_port) [ -z "$LOGTO_CONSOLE_PORT" ] && LOGTO_CONSOLE_PORT="$value" ;;
|
||||||
logto_console_exposed) [ -z "$LOGTO_CONSOLE_EXPOSED" ] && LOGTO_CONSOLE_EXPOSED="$value" ;;
|
logto_console_exposed) [ -z "$LOGTO_CONSOLE_EXPOSED" ] && LOGTO_CONSOLE_EXPOSED="$value" ;;
|
||||||
vendor_enabled) [ -z "$VENDOR_ENABLED" ] && VENDOR_ENABLED="$value" ;;
|
|
||||||
vendor_user) [ -z "$VENDOR_USER" ] && VENDOR_USER="$value" ;;
|
|
||||||
vendor_password) [ -z "$VENDOR_PASS" ] && VENDOR_PASS="$value" ;;
|
|
||||||
monitoring_network) [ -z "$MONITORING_NETWORK" ] && MONITORING_NETWORK="$value" ;;
|
monitoring_network) [ -z "$MONITORING_NETWORK" ] && MONITORING_NETWORK="$value" ;;
|
||||||
version) [ -z "$VERSION" ] && VERSION="$value" ;;
|
version) [ -z "$VERSION" ] && VERSION="$value" ;;
|
||||||
compose_project) [ -z "$COMPOSE_PROJECT" ] && COMPOSE_PROJECT="$value" ;;
|
compose_project) [ -z "$COMPOSE_PROJECT" ] && COMPOSE_PROJECT="$value" ;;
|
||||||
@@ -285,9 +270,6 @@ load_env_overrides() {
|
|||||||
[ -z "$HTTPS_PORT" ] && HTTPS_PORT="$_ENV_HTTPS_PORT"
|
[ -z "$HTTPS_PORT" ] && HTTPS_PORT="$_ENV_HTTPS_PORT"
|
||||||
[ -z "$LOGTO_CONSOLE_PORT" ] && LOGTO_CONSOLE_PORT="$_ENV_LOGTO_CONSOLE_PORT"
|
[ -z "$LOGTO_CONSOLE_PORT" ] && LOGTO_CONSOLE_PORT="$_ENV_LOGTO_CONSOLE_PORT"
|
||||||
[ -z "$LOGTO_CONSOLE_EXPOSED" ] && LOGTO_CONSOLE_EXPOSED="$_ENV_LOGTO_CONSOLE_EXPOSED"
|
[ -z "$LOGTO_CONSOLE_EXPOSED" ] && LOGTO_CONSOLE_EXPOSED="$_ENV_LOGTO_CONSOLE_EXPOSED"
|
||||||
[ -z "$VENDOR_ENABLED" ] && VENDOR_ENABLED="$_ENV_VENDOR_ENABLED"
|
|
||||||
[ -z "$VENDOR_USER" ] && VENDOR_USER="$_ENV_VENDOR_USER"
|
|
||||||
[ -z "$VENDOR_PASS" ] && VENDOR_PASS="$_ENV_VENDOR_PASS"
|
|
||||||
[ -z "$MONITORING_NETWORK" ] && MONITORING_NETWORK="$_ENV_MONITORING_NETWORK"
|
[ -z "$MONITORING_NETWORK" ] && MONITORING_NETWORK="$_ENV_MONITORING_NETWORK"
|
||||||
[ -z "$VERSION" ] && VERSION="${CAMELEER_VERSION:-}"
|
[ -z "$VERSION" ] && VERSION="${CAMELEER_VERSION:-}"
|
||||||
[ -z "$COMPOSE_PROJECT" ] && COMPOSE_PROJECT="$_ENV_COMPOSE_PROJECT"
|
[ -z "$COMPOSE_PROJECT" ] && COMPOSE_PROJECT="$_ENV_COMPOSE_PROJECT"
|
||||||
@@ -437,7 +419,7 @@ run_simple_prompts() {
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " Deployment mode:"
|
echo " Deployment mode:"
|
||||||
echo " [1] Multi-tenant vendor — manage platform, provision tenants on demand"
|
echo " [1] Multi-tenant SaaS — manage platform, provision tenants on demand"
|
||||||
echo " [2] Single-tenant — one server instance, local auth, no identity provider"
|
echo " [2] Single-tenant — one server instance, local auth, no identity provider"
|
||||||
echo ""
|
echo ""
|
||||||
local deploy_choice
|
local deploy_choice
|
||||||
@@ -445,11 +427,9 @@ run_simple_prompts() {
|
|||||||
case "${deploy_choice:-1}" in
|
case "${deploy_choice:-1}" in
|
||||||
2)
|
2)
|
||||||
DEPLOYMENT_MODE="standalone"
|
DEPLOYMENT_MODE="standalone"
|
||||||
VENDOR_ENABLED="false"
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
DEPLOYMENT_MODE="saas"
|
DEPLOYMENT_MODE="saas"
|
||||||
VENDOR_ENABLED="true"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -470,21 +450,6 @@ run_expert_prompts() {
|
|||||||
prompt_password CLICKHOUSE_PASSWORD "ClickHouse password" ""
|
prompt_password CLICKHOUSE_PASSWORD "ClickHouse password" ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
|
||||||
echo ""
|
|
||||||
if prompt_yesno "Enable vendor account?"; then
|
|
||||||
VENDOR_ENABLED="true"
|
|
||||||
prompt VENDOR_USER "Vendor username" "${VENDOR_USER:-$DEFAULT_VENDOR_USER}"
|
|
||||||
if prompt_yesno "Auto-generate vendor password?" "y"; then
|
|
||||||
VENDOR_PASS=""
|
|
||||||
else
|
|
||||||
prompt_password VENDOR_PASS "Vendor password" ""
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
VENDOR_ENABLED="false"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${BOLD} Networking:${NC}"
|
echo -e "${BOLD} Networking:${NC}"
|
||||||
prompt HTTP_PORT "HTTP port" "${HTTP_PORT:-$DEFAULT_HTTP_PORT}"
|
prompt HTTP_PORT "HTTP port" "${HTTP_PORT:-$DEFAULT_HTTP_PORT}"
|
||||||
@@ -523,8 +488,6 @@ merge_config() {
|
|||||||
: "${HTTPS_PORT:=$DEFAULT_HTTPS_PORT}"
|
: "${HTTPS_PORT:=$DEFAULT_HTTPS_PORT}"
|
||||||
: "${LOGTO_CONSOLE_PORT:=$DEFAULT_LOGTO_CONSOLE_PORT}"
|
: "${LOGTO_CONSOLE_PORT:=$DEFAULT_LOGTO_CONSOLE_PORT}"
|
||||||
: "${LOGTO_CONSOLE_EXPOSED:=$DEFAULT_LOGTO_CONSOLE_EXPOSED}"
|
: "${LOGTO_CONSOLE_EXPOSED:=$DEFAULT_LOGTO_CONSOLE_EXPOSED}"
|
||||||
: "${VENDOR_ENABLED:=$DEFAULT_VENDOR_ENABLED}"
|
|
||||||
: "${VENDOR_USER:=$DEFAULT_VENDOR_USER}"
|
|
||||||
: "${VERSION:=$CAMELEER_DEFAULT_VERSION}"
|
: "${VERSION:=$CAMELEER_DEFAULT_VERSION}"
|
||||||
: "${DOCKER_SOCKET:=$DEFAULT_DOCKER_SOCKET}"
|
: "${DOCKER_SOCKET:=$DEFAULT_DOCKER_SOCKET}"
|
||||||
|
|
||||||
@@ -597,10 +560,6 @@ generate_passwords() {
|
|||||||
CLICKHOUSE_PASSWORD=$(generate_password)
|
CLICKHOUSE_PASSWORD=$(generate_password)
|
||||||
log_info "Generated ClickHouse password."
|
log_info "Generated ClickHouse password."
|
||||||
fi
|
fi
|
||||||
if [ "$VENDOR_ENABLED" = "true" ] && [ -z "$VENDOR_PASS" ]; then
|
|
||||||
VENDOR_PASS=$(generate_password)
|
|
||||||
log_info "Generated vendor password."
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- File generation ---
|
# --- File generation ---
|
||||||
@@ -703,11 +662,6 @@ EOF
|
|||||||
|
|
||||||
cat >> "$f" << EOF
|
cat >> "$f" << EOF
|
||||||
|
|
||||||
# Vendor account
|
|
||||||
VENDOR_SEED_ENABLED=${VENDOR_ENABLED}
|
|
||||||
VENDOR_USER=${VENDOR_USER}
|
|
||||||
VENDOR_PASS=${VENDOR_PASS:-}
|
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
DOCKER_SOCKET=${DOCKER_SOCKET}
|
DOCKER_SOCKET=${DOCKER_SOCKET}
|
||||||
DOCKER_GID=$(stat -c '%g' "${DOCKER_SOCKET}" 2>/dev/null || echo "0")
|
DOCKER_GID=$(stat -c '%g' "${DOCKER_SOCKET}" 2>/dev/null || echo "0")
|
||||||
@@ -858,9 +812,6 @@ EOF
|
|||||||
PG_DB_SAAS: cameleer_saas
|
PG_DB_SAAS: cameleer_saas
|
||||||
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
||||||
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:-admin}
|
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:-admin}
|
||||||
VENDOR_SEED_ENABLED: "${VENDOR_SEED_ENABLED:-false}"
|
|
||||||
VENDOR_USER: ${VENDOR_USER:-vendor}
|
|
||||||
VENDOR_PASS: ${VENDOR_PASS:-vendor}
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3001/oidc/.well-known/openid-configuration', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\" && test -f /data/logto-bootstrap.json"]
|
test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3001/oidc/.well-known/openid-configuration', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))\" && test -f /data/logto-bootstrap.json"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -1310,8 +1261,6 @@ http_port=${HTTP_PORT}
|
|||||||
https_port=${HTTPS_PORT}
|
https_port=${HTTPS_PORT}
|
||||||
logto_console_port=${LOGTO_CONSOLE_PORT}
|
logto_console_port=${LOGTO_CONSOLE_PORT}
|
||||||
logto_console_exposed=${LOGTO_CONSOLE_EXPOSED}
|
logto_console_exposed=${LOGTO_CONSOLE_EXPOSED}
|
||||||
vendor_enabled=${VENDOR_ENABLED}
|
|
||||||
vendor_user=${VENDOR_USER}
|
|
||||||
monitoring_network=${MONITORING_NETWORK}
|
monitoring_network=${MONITORING_NETWORK}
|
||||||
version=${VERSION}
|
version=${VERSION}
|
||||||
compose_project=${COMPOSE_PROJECT}
|
compose_project=${COMPOSE_PROJECT}
|
||||||
@@ -1365,17 +1314,6 @@ ClickHouse: default / ${CLICKHOUSE_PASSWORD}
|
|||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if [ "$VENDOR_ENABLED" = "true" ]; then
|
|
||||||
cat >> "$f" << EOF
|
|
||||||
Vendor User: ${VENDOR_USER}
|
|
||||||
Vendor Password: ${VENDOR_PASS}
|
|
||||||
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
echo "Vendor User: (not enabled)" >> "$f"
|
|
||||||
echo "" >> "$f"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then
|
if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then
|
||||||
echo "Logto Console: ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}" >> "$f"
|
echo "Logto Console: ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}" >> "$f"
|
||||||
else
|
else
|
||||||
@@ -1424,9 +1362,9 @@ EOF
|
|||||||
## First Steps
|
## First Steps
|
||||||
|
|
||||||
1. Open the Platform UI in your browser
|
1. Open the Platform UI in your browser
|
||||||
2. Log in with the admin credentials from `credentials.txt`
|
2. Log in as admin with the credentials from `credentials.txt`
|
||||||
3. Create your first tenant via the Vendor console
|
3. Create tenants from the admin console
|
||||||
4. The platform will provision a dedicated server instance for the tenant
|
4. The platform will provision a dedicated server instance for each tenant
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -1475,7 +1413,7 @@ EOF
|
|||||||
cat >> "$f" << 'EOF'
|
cat >> "$f" << 'EOF'
|
||||||
|
|
||||||
The platform generated a self-signed certificate on first boot. To replace it:
|
The platform generated a self-signed certificate on first boot. To replace it:
|
||||||
1. Log in as admin and navigate to **Certificates** in the vendor console
|
1. Log in as admin and navigate to **Certificates** in the admin console
|
||||||
2. Upload your certificate and key via the UI
|
2. Upload your certificate and key via the UI
|
||||||
3. Activate the new certificate (zero-downtime swap)
|
3. Activate the new certificate (zero-downtime swap)
|
||||||
EOF
|
EOF
|
||||||
@@ -1693,11 +1631,6 @@ print_credentials() {
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
||||||
if [ "$VENDOR_ENABLED" = "true" ]; then
|
|
||||||
echo -e " Vendor User: ${BOLD}${VENDOR_USER}${NC}"
|
|
||||||
echo -e " Vendor Password: ${BOLD}${VENDOR_PASS}${NC}"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then
|
if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then
|
||||||
echo -e " Logto Console: ${BLUE}${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}${NC}"
|
echo -e " Logto Console: ${BLUE}${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user