Skip to content

Commit 91f1f5d

Browse files
authored
feat(storage)!: migrate engine storage config to schema (FB-1684) (#25)
# Description Migrate `firebolt-instance-helm` to the **FB-1684** managed-table storage schema (no backward compatibility — the chart ships version-matched with the engine): - `helm/values-dev.yaml` — floci dev config → `managed_table_storage: s3` + `managed_table_bucket_name` + `aws.endpoint` (+ `path_style_addressing: true`); drops `type: minio`/`api_scheme`/`bucket_name`/`minio`. - `helm/templates/engine-statefulset.yaml` + `helm/values.yaml` — add `engineSpec.extraEnv` / `extraEnvFrom`. The FB-1684 schema no longer hardcodes credentials for S3-compatible stores, so callers inject `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` via env (from a Secret in production; `values-dev` sets `firebolt`/`firebolt` for zero-auth floci). - Docs migrate to the new schema, and a new **S3-compatible** page documents Nebius and CoreWeave (`path_style_addressing` is a non-AWS setting). ## ⚠️ Breaking — version-matched with the engine `customEngineConfig.storage` now uses the FB-1684 schema, which a **post-FB-1684 engine** (packdb #23716) requires. Like the operator, the chart is released version-matched with the engine (`appVersion`), so this is the release boundary, not an in-place break. `make dev` needs a post-FB-1684 `:dev` image. # Issue FB-1684 # How Has This Been Tested? - `helm template -f helm/values-dev.yaml` renders the new-schema `customEngineConfig.storage` and the engine `AWS_*` env from `extraEnv`. - `helm lint` (default + dev overlay): 0 failures. # Other comments to the reviewer - `path_style_addressing` applies only to a custom (non-AWS) endpoint; it is ignored for AWS S3. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Breaking storage values affect every install at upgrade and misconfigured env/endpoint can block engines from becoming Ready; changes are mostly config/docs with a small, additive Helm template surface. > > **Overview** > **Breaking release** aligned with post-FB-1684 engines: `customEngineConfig.storage` must use `managed_table_storage`, `managed_table_bucket_name`, and per-cloud `aws` / `gcp` / `azure` blocks. Legacy `type`, `api_scheme`, `bucket_name`, and `minio` / `azurite` shapes are documented as rejected at engine startup. > > The chart adds **`engineSpec.extraEnv` and `engineSpec.extraEnvFrom`** on the engine StatefulSet so S3-compatible stores get `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` from env or Secrets instead of chart-hardcoded creds. **`values-dev`** and the **quickstart** move floci to the new schema plus placeholder AWS env vars. > > Documentation is rewritten across S3, GCS, and ABS guides, adds a dedicated **S3-compatible** page (Nebius, CoreWeave, `path_style_addressing`), updates **security** for credential injection, and registers the new doc route in **docs.json** / **known_pages.json**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 003d79d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 0d0fe7f commit 91f1f5d

11 files changed

Lines changed: 158 additions & 52 deletions

docs/docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"group": "Object Storage",
1818
"pages": [
1919
"usage/object-storage/amazon-s3",
20+
"usage/object-storage/s3-compatible",
2021
"usage/object-storage/google-cloud-storage",
2122
"usage/object-storage/azure-blob-storage"
2223
]

docs/known_pages.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
"/usage/object-storage/azure-blob-storage/",
3030
"/usage/object-storage/google-cloud-storage",
3131
"/usage/object-storage/google-cloud-storage/",
32+
"/usage/object-storage/s3-compatible",
33+
"/usage/object-storage/s3-compatible/",
3234
"/usage/single-engine",
3335
"/usage/single-engine/"
3436
]

docs/quickstart.mdx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,24 @@ floci stores data in the pod's ephemeral filesystem and validates no credentials
7070

7171
## Configure the engine
7272

73-
Create a values file that points the engine's storage at the floci endpoint. The `type: minio` mode signs requests for an S3-compatible endpoint, and `bucket_name` matches the bucket floci created.
73+
Create a values file that points the engine's storage at the floci endpoint. `managed_table_storage: s3` with `aws.endpoint` targets floci, and `managed_table_bucket_name` matches the bucket floci created. floci is zero-auth, so any AWS credentials work (set via `engineSpec.extraEnv`).
7474

7575
```yaml
7676
# my-values.yaml
77+
engineSpec:
78+
extraEnv:
79+
- name: AWS_ACCESS_KEY_ID
80+
value: firebolt
81+
- name: AWS_SECRET_ACCESS_KEY
82+
value: firebolt
83+
7784
customEngineConfig:
7885
storage:
79-
type: minio
80-
api_scheme: "s3://"
81-
bucket_name: firebolt-managed
82-
minio:
86+
managed_table_storage: s3
87+
managed_table_bucket_name: firebolt-managed
88+
aws:
8389
endpoint: http://floci.firebolt.svc.cluster.local:4566
90+
path_style_addressing: true # non-AWS S3-compatible store; ignored for AWS S3
8491
```
8592
8693
This is the only value the local install needs. The chart's defaults provide one engine named `default`, the Envoy gateway, the Metadata Service, and a bundled PostgreSQL.

docs/security.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Object-storage credentials for engines are not represented as Helm values. The c
101101
- Azure: [Microsoft Entra Workload ID](./usage/object-storage/azure-blob-storage#grant-the-engine-an-azure-identity).
102102
- Google Cloud: [Workload Identity Federation for GKE](./usage/object-storage/google-cloud-storage#grant-the-engine-a-google-identity).
103103

104-
The chart never sees those cloud provider credentials. For S3-compatible endpoints that use the `minio` storage type, the endpoint must accept the credentials expected by the engine mode documented in [Amazon S3](./usage/object-storage/amazon-s3#use-an-s3-compatible-endpoint).
104+
The chart never sees those cloud provider credentials. For an S3-compatible endpoint (`managed_table_storage: s3` with `aws.endpoint`), the engine authenticates with the `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` you inject via `engineSpec.extraEnv` (from a Secret in production); see [S3-compatible storage](./usage/object-storage/s3-compatible).
105105

106106
### TLS to PostgreSQL is not exposed
107107

docs/usage/object-storage/amazon-s3.mdx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ sidebarTitle: Amazon S3
44
title: Amazon S3
55
---
66

7+
<Warning>
8+
**Breaking change.** Managed-table storage now uses `managed_table_storage` and `managed_table_bucket_name` with a per-cloud `storage.aws` / `gcp` / `azure` block. The former keys — `type`, `api_scheme`, `bucket_name`, and the `minio` / `azurite` types — are removed and are rejected by the engine at startup. This schema requires a recent engine image; keep the chart and engine on matching versions.
9+
</Warning>
10+
711
This page configures Amazon S3 or an S3-compatible endpoint as engine object storage.
812

913
Every engine needs object storage for managed table data. The chart does not support local-filesystem storage for engines, so an engine pod never becomes Ready until `customEngineConfig.storage` points at object storage.
1014

1115
With object storage as the backing store, durability does not depend on the per-pod data volumes mounted to each engine. Even a complete loss of those volumes does not cause data loss, because the authoritative copy of managed table data lives in the object store.
1216

13-
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `type`, `api_scheme`, and `bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads AWS credentials from the pod's workload identity, which you configure through [AWS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) or [AWS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html).
17+
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `managed_table_storage` and `managed_table_bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads AWS credentials from the pod's workload identity, which you configure through [AWS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) or [AWS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html).
1418

1519
## Prerequisites
1620

@@ -98,9 +102,8 @@ engineSpec:
98102

99103
customEngineConfig:
100104
storage:
101-
type: s3
102-
api_scheme: "s3://"
103-
bucket_name: firebolt-managed
105+
managed_table_storage: s3
106+
managed_table_bucket_name: firebolt-managed
104107
```
105108
106109
Create the ServiceAccount, then install the chart with the matching values:
@@ -115,15 +118,15 @@ helm install firebolt ./helm \
115118
-f my-values.yaml
116119
```
117120

118-
To set the AWS region explicitly, add `region` to the storage block. The EKS identity webhook usually injects the region automatically.
121+
To set the AWS region explicitly, add `region` under `aws`. The EKS identity webhook usually injects the region automatically.
119122

120123
```yaml
121124
customEngineConfig:
122125
storage:
123-
type: s3
124-
api_scheme: "s3://"
125-
bucket_name: firebolt-managed
126-
region: us-east-1
126+
managed_table_storage: s3
127+
managed_table_bucket_name: firebolt-managed
128+
aws:
129+
region: us-east-1
127130
```
128131
129132
### Confirm that object storage works
@@ -150,16 +153,16 @@ New prefixes appear under the bucket as the engine writes data.
150153

151154
## Use an S3-compatible endpoint
152155

153-
For any S3-compatible endpoint reachable from the engine pods, such as self-hosted MinIO, Ceph RGW, or an in-cluster S3 emulator, use `type: minio`. The engine signs requests with the access key and secret key `firebolt` in this mode, so the endpoint must accept those credentials.
156+
For any S3-compatible endpoint reachable from the engine pods, such as self-hosted MinIO, Ceph RGW, or a managed store like Nebius or CoreWeave, set `managed_table_storage: s3` and point `aws.endpoint` at the store. Supply credentials through the engine environment (`engineSpec.extraEnv` / `extraEnvFrom`); a zero-auth emulator accepts any values. See [S3-compatible storage](./s3-compatible) for Nebius and CoreWeave.
154157

155158
```yaml
156159
customEngineConfig:
157160
storage:
158-
type: minio
159-
api_scheme: "s3://"
160-
bucket_name: firebolt-managed
161-
minio:
161+
managed_table_storage: s3
162+
managed_table_bucket_name: firebolt-managed
163+
aws:
162164
endpoint: http://minio.minio.svc.cluster.local:9000
165+
path_style_addressing: true # non-AWS S3-compatible store; ignored for AWS S3
163166
```
164167
165168
`endpoint` must be a URL the engine pod can resolve and reach. Create the bucket out of band before the engine starts.
@@ -179,14 +182,13 @@ Set the intermediary role ARN under `customEngineConfig.storage.aws.intermediary
179182
```yaml
180183
customEngineConfig:
181184
storage:
182-
type: s3
183-
api_scheme: "s3://"
184-
bucket_name: firebolt-managed
185+
managed_table_storage: s3
186+
managed_table_bucket_name: firebolt-managed
185187
aws:
186188
intermediary_access_role: arn:aws:iam::<account-id>:role/firebolt-intermediary
187189
```
188190

189-
The chart passes the `storage.aws` block through unchanged. The block is valid only when `type` is `s3`.
191+
The chart passes the `storage.aws` block through unchanged. The block is valid only when `managed_table_storage` is `s3`.
190192

191193
## Storage scope
192194

docs/usage/object-storage/azure-blob-storage.mdx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ Every engine needs object storage for managed table data. The chart does not sup
1010

1111
With Azure Blob Storage as the backing store, durability does not depend on the per-pod data volumes mounted to each engine. Even a complete loss of those volumes does not cause data loss, because the authoritative copy of managed table data lives in object storage.
1212

13-
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `type`, `api_scheme`, and `bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads Azure credentials from the pod's Azure identity, which you provide with [Microsoft Entra Workload ID](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview).
13+
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `managed_table_storage` and `managed_table_bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads Azure credentials from the pod's Azure identity, which you provide with [Microsoft Entra Workload ID](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview).
1414

1515
<Note>
16-
The chart passes `customEngineConfig.storage` through unchanged and does not validate the `type`. The `abs` backend requires an engine image that supports it. An unsupported `type` is written verbatim into the engine `config.yaml`, so the engine fails at startup rather than at install time.
16+
The chart passes `customEngineConfig.storage` through unchanged and does not validate `managed_table_storage`. The `abs` backend requires an engine image that supports it. An unsupported value is written verbatim into the engine `config.yaml`, so the engine fails at startup rather than at install time.
1717
</Note>
1818

1919
## Prerequisites
@@ -117,7 +117,7 @@ metadata:
117117
118118
### Point the chart at the container
119119
120-
Run the engine pods under the annotated ServiceAccount, label them so Workload ID injects credentials, and set the storage block to the container. The default scheme for `abs` is `azure://`, `bucket_name` is the container name, and `azure.storage_account_name` is the storage account that holds it.
120+
Run the engine pods under the annotated ServiceAccount, label them so Workload ID injects credentials, and set the storage block to the container. `managed_table_bucket_name` is the container name, and `azure.storage_account_name` is the storage account that holds it.
121121

122122
```yaml
123123
# my-values.yaml
@@ -132,9 +132,8 @@ engines:
132132
133133
customEngineConfig:
134134
storage:
135-
type: abs
136-
api_scheme: "azure://"
137-
bucket_name: firebolt-managed
135+
managed_table_storage: abs
136+
managed_table_bucket_name: firebolt-managed
138137
azure:
139138
storage_account_name: fireboltenginedemo
140139
```
@@ -192,15 +191,14 @@ Set its application client ID under `customEngineConfig.storage.azure.intermedia
192191
```yaml
193192
customEngineConfig:
194193
storage:
195-
type: abs
196-
api_scheme: "azure://"
197-
bucket_name: firebolt-managed
194+
managed_table_storage: abs
195+
managed_table_bucket_name: firebolt-managed
198196
azure:
199197
storage_account_name: fireboltenginedemo
200198
intermediary_service_principal_client_id: 35f11db5-082b-46e8-9f2f-5466d8630003
201199
```
202200

203-
The chart passes the `storage.azure` block through unchanged. The block is valid when `type` is `abs` or `azurite`.
201+
The chart passes the `storage.azure` block through unchanged. The block is valid when `managed_table_storage` is `abs`.
204202

205203
## Storage scope
206204

docs/usage/object-storage/google-cloud-storage.mdx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ Every engine needs object storage for managed table data. The chart does not sup
1010

1111
With Google Cloud Storage as the backing store, durability does not depend on the per-pod data volumes mounted to each engine. Even a complete loss of those volumes does not cause data loss, because the authoritative copy of managed table data lives in the bucket.
1212

13-
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `type`, `api_scheme`, and `bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads Google Cloud credentials from the pod's Google identity, which you provide with [Workload Identity Federation for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity).
13+
You configure object storage on the engine through `customEngineConfig.storage`, which the chart passes through unchanged into the engine's `config.yaml`. The `managed_table_storage` and `managed_table_bucket_name` keys match the Firebolt Core configuration schema, and the chart does not validate them. The engine reads Google Cloud credentials from the pod's Google identity, which you provide with [Workload Identity Federation for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity).
1414

1515
<Note>
16-
The chart passes `customEngineConfig.storage` through unchanged and does not validate the `type`. The `gcs` backend requires an engine image that supports it. An unsupported `type` is written verbatim into the engine `config.yaml`, so the engine fails at startup rather than at install time.
16+
The chart passes `customEngineConfig.storage` through unchanged and does not validate `managed_table_storage`. The `gcs` backend requires an engine image that supports it. An unsupported value is written verbatim into the engine `config.yaml`, so the engine fails at startup rather than at install time.
1717
</Note>
1818

1919
## Prerequisites
@@ -99,9 +99,8 @@ engineSpec:
9999
100100
customEngineConfig:
101101
storage:
102-
type: gcs
103-
api_scheme: "gs://"
104-
bucket_name: firebolt-managed
102+
managed_table_storage: gcs
103+
managed_table_bucket_name: firebolt-managed
105104
```
106105

107106
Create the ServiceAccount, then install the chart with the matching values:
@@ -153,14 +152,13 @@ Set its ID under `customEngineConfig.storage.gcp.intermediary_service_account_id
153152
```yaml
154153
customEngineConfig:
155154
storage:
156-
type: gcs
157-
api_scheme: "gs://"
158-
bucket_name: firebolt-managed
155+
managed_table_storage: gcs
156+
managed_table_bucket_name: firebolt-managed
159157
gcp:
160158
intermediary_service_account_id: projects/my-project/serviceAccounts/firebolt-intermediary@my-project.iam.gserviceaccount.com
161159
```
162160

163-
The chart passes the `storage.gcp` block through unchanged. The block is valid only when `type` is `gcs`.
161+
The chart passes the `storage.gcp` block through unchanged. The block is valid only when `managed_table_storage` is `gcs`.
164162

165163
## Storage scope
166164

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
title: S3-compatible storage
3+
description: Back Firebolt engines with a non-AWS S3-compatible object store (Nebius, CoreWeave, MinIO) using firebolt-instance-helm.
4+
sidebarTitle: S3-compatible
5+
---
6+
7+
<Warning>
8+
**Breaking change.** Managed-table storage now uses `managed_table_storage` and `managed_table_bucket_name` with a per-cloud `storage.aws` / `gcp` / `azure` block. The former keys — `type`, `api_scheme`, `bucket_name`, and the `minio` / `azurite` types — are removed and are rejected by the engine at startup. This schema requires a recent engine image; keep the chart and engine on matching versions.
9+
</Warning>
10+
11+
Besides Amazon S3, the engine can use any **S3-compatible** object store — for example [Nebius](https://nebius.com/) Object Storage, [CoreWeave](https://www.coreweave.com/) Object Storage, or a self-hosted [MinIO](https://min.io/). You point the engine at the store's endpoint and supply credentials through the engine container environment.
12+
13+
## How it differs from Amazon S3
14+
15+
For [Amazon S3](./amazon-s3) you set only `managed_table_storage` and `managed_table_bucket_name`, and credentials come from the pod's AWS identity (IRSA / Pod Identity). For an S3-compatible store you additionally set, under `storage.aws`:
16+
17+
- `endpoint` — the store's S3 API endpoint (`https://…`).
18+
- `path_style_addressing` — the addressing style. **This applies only to a custom (non-AWS) endpoint; it is ignored for Amazon S3.**
19+
- `true` (path-style, `endpoint/bucket/key`) — the default. Used by MinIO and Nebius.
20+
- `false` (virtual-hosted, `bucket.endpoint/key`) — required by providers that support virtual-hosted addressing only, such as CoreWeave.
21+
- `verify_ssl` — set to `false` only for a store with a self-signed certificate or plain HTTP.
22+
23+
Credentials are read from the AWS SDK environment chain. Inject `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` into the engine container with `engineSpec.extraEnv` (or `engineSpec.extraEnvFrom` to pull them from a `Secret`).
24+
25+
## Nebius Object Storage
26+
27+
Nebius exposes an S3 API at `https://storage.<region>.nebius.cloud` and supports path-style addressing (the default).
28+
29+
Create a `Secret` from a Nebius static access key:
30+
31+
```bash
32+
kubectl -n firebolt create secret generic nebius-s3-credentials \
33+
--from-literal=AWS_ACCESS_KEY_ID=<nebius-access-key-id> \
34+
--from-literal=AWS_SECRET_ACCESS_KEY=<nebius-secret>
35+
```
36+
37+
```yaml
38+
# my-values.yaml
39+
engineSpec:
40+
extraEnvFrom:
41+
- secretRef:
42+
name: nebius-s3-credentials
43+
44+
customEngineConfig:
45+
storage:
46+
managed_table_storage: s3
47+
managed_table_bucket_name: my-firebolt-bucket
48+
aws:
49+
endpoint: https://storage.us-central1.nebius.cloud
50+
path_style_addressing: true # non-AWS S3-compatible store; ignored for AWS S3
51+
```
52+
53+
## CoreWeave Object Storage
54+
55+
CoreWeave Object Storage supports virtual-hosted addressing only, so set `path_style_addressing: false`. Use the endpoint for your CoreWeave Object Storage account, and create a `Secret` (`coreweave-s3-credentials`) the same way.
56+
57+
```yaml
58+
# my-values.yaml
59+
engineSpec:
60+
extraEnvFrom:
61+
- secretRef:
62+
name: coreweave-s3-credentials
63+
64+
customEngineConfig:
65+
storage:
66+
managed_table_storage: s3
67+
managed_table_bucket_name: my-firebolt-bucket
68+
aws:
69+
endpoint: https://<coreweave-object-storage-endpoint>
70+
path_style_addressing: false # CoreWeave supports virtual-hosted addressing only
71+
```
72+
73+
## Confirm that object storage works
74+
75+
Install the chart with your values, wait for the engine to become `Ready`, then create a table and insert a row (see the [Quickstart](../../quickstart) for connecting to the engine). New object-storage prefixes appear under your bucket as the engine writes data — list them with your provider's CLI (`aws s3 ls s3://my-firebolt-bucket --endpoint-url <endpoint>`).

helm/templates/engine-statefulset.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ spec:
124124
# startup.
125125
- name: FIREBOLT_CORE_MODE
126126
value: "1"
127+
{{- with $.Values.engineSpec.extraEnv }}
128+
{{- toYaml . | nindent 12 }}
129+
{{- end }}
130+
{{- with $.Values.engineSpec.extraEnvFrom }}
131+
envFrom:
132+
{{- toYaml . | nindent 12 }}
133+
{{- end }}
127134
command: ["/bin/bash", "-c"]
128135
tty: true
129136
stdin: true

0 commit comments

Comments
 (0)