mengw15 opened a new issue, #6870:
URL: https://github.com/apache/texera/issues/6870

   ### Feature Summary
   
   ## Background
   
   Every execution's outputs — results, runtime statistics, and console logs — 
are currently
   written to a single shared Iceberg warehouse, with the platform absorbing 
the S3 cost. There
   is no per-tenant storage isolation, and no way to attribute storage cost to 
the user who owns
   the data. Design discussion: #5293.
   
   ## Goal
   
   Let each user register **their own S3 bucket** as a *warehouse*. A workflow 
execution writes
   its Iceberg tables (results / runtime statistics / console messages) into 
the selected
   warehouse's bucket, so:
   - storage cost is attributed to the user who owns the data,
   - per-user warehouses provide per-tenant isolation,
   - users who bring their own storage keep full control of their data.
   
   ## Architecture
   
   <img width="1048" height="540" alt="Image" 
src="https://github.com/user-attachments/assets/e63c4869-832f-46aa-8ea7-446148b369f9";
 />
       
   ## Design
   
   **Warehouse (Design 2, #5293).** A warehouse is a Lakekeeper (Iceberg REST) 
catalog entity
   backed by the user's S3 bucket, holding the execution namespaces (results, 
runtime statistics,
   console messages) plus its storage configuration. Each warehouse is a 
distinct Lakekeeper
   warehouse with its own key-prefix in the bucket. It is selected **per 
execution**, decoupled
   from the computing unit.
   
   **Two-layer runtime.**
   - *Catalog path* — a per-warehouse REST catalog client talks to Lakekeeper 
for metadata.
   - *Data path* — Iceberg reads/writes Parquet **directly** to the user's S3 
using Lakekeeper-vended
     short-lived credentials.
   
   **Credentials: assume-role, no static keys.** The user grants Texera an IAM 
role; the **platform
   principal** (this deployment's AWS identity, provisioned once by the 
operator) assumes it via AWS
   STS, gated by a **per-warehouse external ID**; workers receive only 
short-lived STS credentials,
   vended per execution. The external ID is **server-minted** by the Texera web 
service (the client cannot
   choose it — this prevents registering another user's role ARN + external ID 
to reach their
   bucket), **per-warehouse**, and **unguessable (UUID)**; it is reserved 
**before** create so the
   user wires their role's trust policy in one step (no reveal round-trip). 
Texera stores only
   **non-secret metadata** — the Lakekeeper warehouse id, role ARN, and 
external ID — never raw S3
   keys. Assuming a role requires all three at once (platform credentials + 
external ID + role ARN),
   so a leaked role ARN + external ID grant nothing on their own.
   
   **Warehouse types (flavor).** *Cloud* (AWS) uses the assume-role flow above. 
*Local* uses this
   deployment's built-in MinIO (dev / on-prem), where the platform supplies the 
storage.
   
   ## Warehouse setup (user side, Cloud/AWS)
   
   When the user opens the Cloud form, Texera shows the **platform principal 
ARN** and a reserved
   **external ID**. The user creates one IAM role with:
   
   **Trust policy** — allow the platform principal to assume the role, gated by 
the external ID:
   ```json
   {
     "Version": "2012-10-17",
     "Statement": [{
       "Effect": "Allow",
       "Principal": { "AWS": "<platform-principal-arn>" },
       "Action": "sts:AssumeRole",
       "Condition": { "StringEquals": { "sts:ExternalId": "<external-id>" } }
     }]
   }
   ```
   
   **Permission policy** — grant the role access to the bucket:
   ```json
   {
     "Version": "2012-10-17",
     "Statement": [{
       "Effect": "Allow",
       "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", 
"s3:ListBucket", "s3:GetBucketLocation"],
       "Resource": ["arn:aws:s3:::<bucket>", "arn:aws:s3:::<bucket>/*"]
     }]
   }
   ```
   
   ## Warehouse lifecycle
   
   - **Create** — reserve identity (external ID + platform principal ARN) → 
user creates the IAM
     role (policies above) → submit bucket / region / role ARN → Texera (via 
Lakekeeper) validates
     by **actually assuming the role and test-writing to S3**. A wrong role ARN 
/ external ID /
     bucket fails **at create time** (HTTP 502), before any record is written — 
no orphaned state.
   - **Delete** — the warehouse is emptied in the catalog first (Lakekeeper 
refuses to drop a
     non-empty warehouse), dropping tables without purge so the **S3 data files 
are kept** — it is
     the user's bucket; the user cleans it up themselves.
   
   ## Implementation surface
   
   - **Backend** — `WarehouseResource` (REST) · `LakekeeperClient` (warehouse 
management +
     empty-first delete) · `StorageConfig` (the `storage.warehouse.enabled` 
flag) · `WorkflowService`
     (resolves the per-execution warehouse, ownership-checked) · per-warehouse 
`IcebergCatalogInstance`
     cache · warehouse-scoped storage URIs (`DocumentFactory` / 
`VFSURIFactory`).
   - **Schema** — `user_warehouse`, `user_s3_pending_identity`.
   - **Frontend** — Warehouse tab, on-canvas per-execution picker, AWS IAM-role 
warehouse form,
     warehouse service.
   
   ## Scope & rollout
   
   - **Target: multi-tenant (Kubernetes) REST-catalog deployments.** 
Single-node / local Docker
     Compose is unchanged — the Postgres catalog and the single shared 
Lakekeeper warehouse keep
     working.
   - Ships behind a **default-off** flag (`storage.warehouse.enabled`). With 
the flag off, storage
     behaves exactly as it does today. Deployments opt in once catalog-side 
authentication (see
     follow-ups) is in place.
   
   ## Sub-issues (each → one PR)
   
   - [ ] Storage foundation: per-warehouse Iceberg catalog + warehouse-scoped 
storage URIs (backward-compatible no-op)
   - [ ] Feature flag (storage.warehouse.enabled, default off)
   - [ ] Schema: `user_warehouse`
   - [ ] Warehouse REST endpoints + Lakekeeper client + per-execution injection
   - [ ] Frontend: warehouse tab + on-canvas per-execution picker
   - [ ] Schema: assume-role fields (role ARN / external ID / pending identity)
   - [ ] Backend: assume-role warehouse creation + reserve-identity
   - [ ] Frontend: AWS IAM-role warehouse form
   
   ## Follow-ups (out of scope here)
   
   - **Catalog-side authentication** — the compute↔Lakekeeper channel is 
currently unauthenticated;
     a per-execution scoped token validated by the catalog (Lakekeeper OIDC + 
per-warehouse
     authorization) is required before enabling the feature in a multi-tenant 
deployment.
   - **Warehouse sharing** — per-warehouse access control (ACL) for 
collaboration.
   
   
   ### Proposed Solution or Design
   
   1
   
   ### Affected Area
   
   Storage / Metadata


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to