Skip to content

Route buckets per backend + make the multi-backend functional test real - #22

Merged
CRThaze merged 1 commit into
mainfrom
CRThaze/s3proxy-multi-backend-routing
Jul 21, 2026
Merged

Route buckets per backend + make the multi-backend functional test real#22
CRThaze merged 1 commit into
mainfrom
CRThaze/s3proxy-multi-backend-routing

Conversation

@CRThaze

@CRThaze CRThaze commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Why

The multi-backend functional leg enabled s3 + azureblob + filesystem in one release but only ever exercised one backend. The chart had no way to route a bucket to a specific backend, so S3Proxy served every bucket from the first (default) backend; the leg passed green without ever touching azureblob or s3. This change makes it actually route to and verify each backend.

Chart changes

  • Per-backend bucket-locator. s3proxy.bucket-locator.N was emitted in the shared config block, so the same global list was copied into every backend's properties file. S3Proxy de-dupes locators across --properties files (first file wins), so only the first backend ever honored them. Now each backend renders its own locators from config.backends.<name>.bucketLocators, and the global config.buckets.locator is removed.
  • Per-backend credentials. The single shared secret.properties emitted only the first-enabled backend's jclouds.credential and was appended to every backend file, so azureblob got s3's credential. It is replaced with secret-common.properties (client auth, appended to all) plus per-backend secret-<name>.properties; the merge initContainer appends common plus the matching backend secret, so each backend gets only its own credential. This also fixes a latent GCS jclouds.credential=jclouds.credential= double-prefix.
  • azureblob endpoint. Emit the provider-agnostic jclouds.endpoint (previously the jclouds.azureblob.endpoint typo) and render the computed default endpoint when only account is set.

Test changes

  • ci/functional/values/multi-backend.yaml routes smoke-s3-*/smoke-az-*/smoke-fs-* to their backends. azureblob uses the azureblob-sdk provider, which signs correctly against Azurite; the legacy azureblob provider mis-signs SharedKey and Azurite returns 403 (verified on kind).
  • New ci/functional/assert-routing.sh: it writes one bucket per backend through s3proxy and verifies each object physically lands on its intended backend (MinIO via the S3 API for s3, Azurite via the az CLI for azureblob, filesystem by elimination), and that no bucket leaks into another backend's store.
  • The Azurite mock runs with --skipApiVersionCheck. The assertion's az CLI on the CI runner sends a newer x-ms-version than the pinned Azurite image knows, which it would otherwise reject (InvalidHeaderValue). The s3proxy azureblob-sdk path is unaffected.
  • .github/workflows/functional-test.yaml: the multi-backend and azureblob legs are now hard gates (all soft_fail removed); multi-backend runs the routing assertion instead of the plain round-trip.

Verification (local kind, end-to-end)

  • multi-backend: routing is exclusive. smoke-s3 goes to MinIO, smoke-az to Azurite, smoke-fs to filesystem, with no cross-leaks.
  • azureblob-only, s3-only, filesystem-only: all pass (the secret-merge rework does not regress single-backend deployments).
  • helm lint, kubeconform -strict (k8s 1.29, all test-values), actionlint, shellcheck: clean.

Notes

  • No Chart.yaml version bump (handled separately), so verify-version fails by design for now.
  • The repo's helm-docs action regenerates the root README.md from README.md.gotmpl on the PR; only the template is edited here.
  • The chart default azureblob provider is left as azureblob. Whether to make azureblob-sdk the default is left to the dedicated azureblob ticket (DND-1416); this PR only sets it in the functional test values.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…to-end

The multi-backend functional test configured s3 + azureblob + filesystem but
only ever exercised one backend: the chart had no way to route a bucket to a
specific backend, so S3Proxy served every bucket from the first (default)
backend. The leg passed without touching azureblob or s3 — a false green.

Chart:
- Per-backend bucket-locator. Move s3proxy.bucket-locator.N out of the shared
  config block (which copied one global list into every backend file, so
  S3Proxy's first-file-wins de-dup meant only the first backend honored it) into
  each backend's own properties, driven by config.backends.<name>.bucketLocators.
- Per-backend credentials. Replace the single shared secret.properties (which
  emitted only the first-enabled backend's jclouds.credential and appended it to
  every backend file) with secret-common.properties + per-backend
  secret-<name>.properties; the merge initContainer appends common + the matching
  backend secret, so each backend gets only its own credential. Also fixes a
  latent GCS double-"jclouds.credential=" prefix.
- azureblob: emit the provider-agnostic jclouds.endpoint (was the
  jclouds.azureblob.endpoint typo) and render the computed default endpoint when
  only account is set.

Test:
- ci/functional/values/multi-backend.yaml routes smoke-s3-*/smoke-az-*/smoke-fs-*
  to their backends; azureblob uses the azureblob-sdk provider, which signs
  correctly against Azurite (the legacy azureblob provider mis-signs -> 403).
- ci/functional/assert-routing.sh writes one bucket per backend through s3proxy
  and verifies each object physically lands on its intended backend (MinIO for
  s3, Azurite for azureblob, filesystem by elimination) and that no bucket leaks
  into another backend.
- Azurite mock runs with --skipApiVersionCheck: the assertion's az CLI on the CI
  runner sends a newer x-ms-version than the Azurite image knows, which it would
  otherwise reject (InvalidHeaderValue). The s3proxy azureblob-sdk path is
  unaffected.
- functional-test.yaml: multi-backend and azureblob legs are now hard gates
  (all soft_fail removed).

No Chart.yaml version bump (handled separately), so verify-version fails by
design for now.

Verified on kind: multi-backend routing exclusive (s3->MinIO, az->Azurite,
fs->filesystem); azureblob-only, s3-only, filesystem-only all pass.
@CRThaze
CRThaze force-pushed the CRThaze/s3proxy-multi-backend-routing branch from 105af9e to 453d241 Compare July 21, 2026 10:18
@github-actions

Copy link
Copy Markdown

📊 Helm Render Diff Summary

Chart charts/s3proxy rendered with Kubernetes 1.29.0. Informational only — this check never fails the PR.

Values File Chart Path Changes Status
test-values/azureblob.yaml charts/s3proxy +33 -12 🔄 Changes Detected (summary)
test-values/b2.yaml charts/s3proxy +32 -12 🔄 Changes Detected (summary)
test-values/filesystem.yaml charts/s3proxy +30 -11 🔄 Changes Detected (summary)
test-values/gcs.yaml charts/s3proxy +30 -11 🔄 Changes Detected (summary)
test-values/ingress.yaml charts/s3proxy +30 -11 🔄 Changes Detected (summary)
test-values/multi-backend.yaml charts/s3proxy +37 -13 🔄 Changes Detected (summary)
test-values/openstack-swift.yaml charts/s3proxy +32 -12 🔄 Changes Detected (summary)
test-values/rackspace.yaml charts/s3proxy +32 -12 🔄 Changes Detected (summary)
test-values/s3.yaml charts/s3proxy +32 -12 🔄 Changes Detected (summary)
test-values/transient.yaml charts/s3proxy +30 -11 🔄 Changes Detected (summary)

🔍 Detailed Changes

📝 Changes in charts/s3proxy with test-values/azureblob.yaml

🔍 Click to view complete diff
--- /tmp/before-azureblob.yaml	2026-07-21 10:18:59.634315222 +0000
+++ /tmp/after-azureblob.yaml	2026-07-21 10:18:59.598314996 +0000
@@ -12,12 +12,18 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
+  secret-azureblob.properties: |
     # Azure Blob backend credentials
     jclouds.credential=dGVzdC1henVyZS1hY2NvdW50LWtleQ==
 ---
@@ -43,6 +49,7 @@
 
     # Azure Blob backend configuration
     jclouds.provider=azureblob
+    jclouds.endpoint=https://teststorageaccount.blob.core.windows.net
     jclouds.identity=teststorageaccount
     # Credentials will be merged from the secret properties file
 ---
@@ -88,8 +95,8 @@
   template:
     metadata:
       annotations:
-        checksum/config: 368a86a0463c03390ce0ac332db92ab614ca95e45578999dd3756542b5d12b38
-        checksum/secret: 640c0029bd17c90a101c4ac4c096503cb460e906ae5d52f3f9c452c46ed52f00
+        checksum/config: d6c39e20a35ed7d5bba241876e269b6b133c335d1eedcc0afc15bd6ed93cbcac
+        checksum/secret: cecb329ab8cec440d9bb23c1966bd1cad7a6faf0482210aad62b68784724fbff
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -109,15 +116,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -126,11 +136,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/b2.yaml

🔍 Click to view complete diff
--- /tmp/before-b2.yaml	2026-07-21 10:18:59.723315781 +0000
+++ /tmp/after-b2.yaml	2026-07-21 10:18:59.676315486 +0000
@@ -12,13 +12,19 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
-    # Backblaze B2 backend credentials
+  secret-b2.properties: |
+    # Backblaze B2 backend credential
     jclouds.credential=b2-application-key
 ---
 # Source: s3proxy/templates/configmap.yaml
@@ -89,7 +95,7 @@
     metadata:
       annotations:
         checksum/config: 96722c84e4599eb17a84456e126d3584b09f772d606acbdd8796e130b13d95b9
-        checksum/secret: 29135c662d4c12acbe3e810f50e565ffe35358e71f1d73cdeb2ef9332937ba86
+        checksum/secret: b40863588f7aeb0a4352c7ffbeca4ab1e2092f46f2a779c8094a0248f609d4fe
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -109,15 +115,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -126,11 +135,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/filesystem.yaml

🔍 Click to view complete diff
--- /tmp/before-filesystem.yaml	2026-07-21 10:18:59.823316409 +0000
+++ /tmp/after-filesystem.yaml	2026-07-21 10:18:59.782316151 +0000
@@ -12,10 +12,15 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
 ---
@@ -108,7 +113,7 @@
     metadata:
       annotations:
         checksum/config: bc6ced17a1db59bee1d2e69c157cee312ee761780fe81dc307e528e361680eba
-        checksum/secret: 6437a12db0ae604ebc94ad01e0fc59331fd122ac38c8ee8b3200739717331e29
+        checksum/secret: db3f2d4aa1a846c4f14b01ad00e76ecfa1a92cf5334b5ef423dd5d4bcf639b9d
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -128,15 +133,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -145,11 +153,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/gcs.yaml

🔍 Click to view complete diff
--- /tmp/before-gcs.yaml	2026-07-21 10:18:59.915316986 +0000
+++ /tmp/after-gcs.yaml	2026-07-21 10:18:59.876316742 +0000
@@ -12,10 +12,15 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
 ---
@@ -89,7 +94,7 @@
     metadata:
       annotations:
         checksum/config: 40dd30e644899a23278aa57062ac254ebf250f93588d62e4f10e7ac742216a29
-        checksum/secret: 6437a12db0ae604ebc94ad01e0fc59331fd122ac38c8ee8b3200739717331e29
+        checksum/secret: db3f2d4aa1a846c4f14b01ad00e76ecfa1a92cf5334b5ef423dd5d4bcf639b9d
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -109,15 +114,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -126,11 +134,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/ingress.yaml

🔍 Click to view complete diff
--- /tmp/before-ingress.yaml	2026-07-21 10:19:00.000317520 +0000
+++ /tmp/after-ingress.yaml	2026-07-21 10:18:59.958317256 +0000
@@ -24,10 +24,15 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
 ---
@@ -125,7 +130,7 @@
     metadata:
       annotations:
         checksum/config: e868fdb1d0fc6df03964c52acccbdbff78413f7722cc47a24b999b4f9acab8d8
-        checksum/secret: 6437a12db0ae604ebc94ad01e0fc59331fd122ac38c8ee8b3200739717331e29
+        checksum/secret: db3f2d4aa1a846c4f14b01ad00e76ecfa1a92cf5334b5ef423dd5d4bcf639b9d
         prometheus.io/scrape: "true"
       labels:
         app.kubernetes.io/name: s3proxy
@@ -148,15 +153,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -165,11 +173,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/multi-backend.yaml

🔍 Click to view complete diff
--- /tmp/before-multi-backend.yaml	2026-07-21 10:19:00.093318104 +0000
+++ /tmp/after-multi-backend.yaml	2026-07-21 10:19:00.047317815 +0000
@@ -12,14 +12,23 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
-    # S3 backend credentials
+  secret-s3.properties: |
+    # S3 backend credential
     jclouds.credential=minio-secret-key
+  secret-azureblob.properties: |
+    # Azure Blob backend credentials
+    jclouds.credential=dGVzdC1henVyZS1hY2NvdW50LWtleQ==
 ---
 # Source: s3proxy/templates/configmap.yaml
 apiVersion: v1
@@ -57,6 +66,7 @@
 
     # Azure Blob backend configuration
     jclouds.provider=azureblob
+    jclouds.endpoint=https://teststorageaccount.blob.core.windows.net
     jclouds.identity=teststorageaccount
     # Credentials will be merged from the secret properties file
 ---
@@ -102,8 +112,8 @@
   template:
     metadata:
       annotations:
-        checksum/config: fcacd51eade5ddc2196538672950a68b7f834951463de70657e32aebbc756a6c
-        checksum/secret: 0c309bcc87cf3ba962222fb9af000518ad5251e2b0d205ede5d23de8cdebcfd1
+        checksum/config: 2507f2787cb1b6e10c5007cd4df78a8549e49d0f4f91054b64f299ec7e7d3e9a
+        checksum/secret: a1e86b83aa15d09d804350525b275f845d67ed499261c128a87197e00816d291
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -123,15 +133,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -140,11 +153,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/openstack-swift.yaml

🔍 Click to view complete diff
--- /tmp/before-openstack-swift.yaml	2026-07-21 10:19:00.177318631 +0000
+++ /tmp/after-openstack-swift.yaml	2026-07-21 10:19:00.138318386 +0000
@@ -12,13 +12,19 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
-    # OpenStack Swift backend credentials
+  secret-openstack-swift.properties: |
+    # OpenStack Swift backend credential
     jclouds.credential=test-password
 ---
 # Source: s3proxy/templates/configmap.yaml
@@ -91,7 +97,7 @@
     metadata:
       annotations:
         checksum/config: ace03fa8e146d3ed7ee57b62e47eda53b3ccbf1eabc9a48068172a73864f4d22
-        checksum/secret: 3d5d17e86c1731c633808a27afa09ef78dede3f6f1fbbe4b4102e5904098fb26
+        checksum/secret: 8f83299b2dd52d948e3b5e1ae4f81cfdb1c37e6991a6ae507ec75342662279b7
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -111,15 +117,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -128,11 +137,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/rackspace.yaml

🔍 Click to view complete diff
--- /tmp/before-rackspace.yaml	2026-07-21 10:19:00.258319140 +0000
+++ /tmp/after-rackspace.yaml	2026-07-21 10:19:00.221318907 +0000
@@ -12,13 +12,19 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
-    # Rackspace Cloud Files backend credentials
+  secret-rackspace-cloudfiles.properties: |
+    # Rackspace Cloud Files backend credential
     jclouds.credential=test-api-key
 ---
 # Source: s3proxy/templates/configmap.yaml
@@ -89,7 +95,7 @@
     metadata:
       annotations:
         checksum/config: 4ff649b449ab7a5348214246b7c41e3d0ee322033cdb05d744e6ba49871b32f2
-        checksum/secret: bdd2dfd3861cfc502edd34a1f5207b00ad23594f030b7b562f88ff37c9818199
+        checksum/secret: d3f8e3438c5361982a50c46c541f0b8d303d59793e2d41c8f2a3089c63620c21
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -109,15 +115,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -126,11 +135,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/s3.yaml

🔍 Click to view complete diff
--- /tmp/before-s3.yaml	2026-07-21 10:19:00.337319636 +0000
+++ /tmp/after-s3.yaml	2026-07-21 10:19:00.301319410 +0000
@@ -12,13 +12,19 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
-    # S3 backend credentials
+  secret-s3.properties: |
+    # S3 backend credential
     jclouds.credential=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
 ---
 # Source: s3proxy/templates/configmap.yaml
@@ -91,7 +97,7 @@
     metadata:
       annotations:
         checksum/config: 37f9a030f7c49caa19dd586404e829e9ef4511a27fa805421703cdb09dc3386a
-        checksum/secret: d1e8db856a78ae43b2c308164ea5e575de7b0f6db34580c9ce0059358c1bfad5
+        checksum/secret: 2dad71e864d08e8a544c786da8c1eed11ec37b6e5116fd2c4580a8d8acc3b737
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -111,15 +117,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -128,11 +137,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

📝 Changes in charts/s3proxy with test-values/transient.yaml

🔍 Click to view complete diff
--- /tmp/before-transient.yaml	2026-07-21 10:19:00.435320251 +0000
+++ /tmp/after-transient.yaml	2026-07-21 10:19:00.393319987 +0000
@@ -12,10 +12,15 @@
     app.kubernetes.io/managed-by: Helm
 type: Opaque
 stringData:
-  # Properties file containing sensitive configuration values
-  # This will be merged with the backend properties files by the init container
-  secret.properties: |
-    # S3Proxy authentication credentials (for clients connecting to s3proxy)
+  # Sensitive properties merged into the backend properties files by the
+  # merge-configs initContainer:
+  #   * secret-common.properties  -> appended to EVERY backend file (client auth).
+  #   * secret-<backend>.properties -> appended ONLY to that backend's file, so
+  #     each backend gets its own jclouds.credential and never another backend's.
+  # Local backends (filesystem/transient) need no secret file; their placeholder
+  # jclouds.identity/credential come from the ConfigMap.
+  secret-common.properties: |
+    # S3Proxy client authentication credentials (shared by all backends)
     s3proxy.identity=test-access-key
     s3proxy.credential=test-secret-key
 ---
@@ -89,7 +94,7 @@
     metadata:
       annotations:
         checksum/config: e9d12802113265af5f82907dbafd0082704fd2e0edf1ace6ef6a40c3d43d6b63
-        checksum/secret: 6437a12db0ae604ebc94ad01e0fc59331fd122ac38c8ee8b3200739717331e29
+        checksum/secret: db3f2d4aa1a846c4f14b01ad00e76ecfa1a92cf5334b5ef423dd5d4bcf639b9d
       labels:
         app.kubernetes.io/name: s3proxy
         app.kubernetes.io/instance: release
@@ -109,15 +114,18 @@
               set -e
               echo "Merging configuration files..."
 
-              # Check if secret properties file exists
-              SECRET_FILE="/secret/secret.properties"
+              # secret-common.properties holds the client-facing auth and is
+              # appended to every backend file. Each backend additionally gets
+              # its own secret-<backend>.properties (its jclouds.credential), so
+              # one backend's credential never leaks into another's file.
+              COMMON_SECRET="/secret/secret-common.properties"
 
               # Loop through all properties files in the config directory
               for config_file in /config/*.properties
               do
                 if [ -f "$config_file" ]
                 then
-                  # Get the filename
+                  # Get the filename, e.g. backend-s3.properties
                   filename=$(basename "$config_file")
                   output_file="/merged-config/$filename"
 
@@ -126,11 +134,22 @@
                   # Copy base config file to output
                   cp "$config_file" "$output_file"
 
-                  # If secret file exists, append its contents (overriding duplicates)
-                  if [ -f "$SECRET_FILE" ]
+                  # Append the shared client-auth secret, if present
+                  if [ -f "$COMMON_SECRET" ]
                   then
                     echo "" >> "$output_file"  # Add newline separator
-                    cat "$SECRET_FILE" >> "$output_file"
+                    cat "$COMMON_SECRET" >> "$output_file"
+                  fi
+
+                  # Append this backend's own secret: backend-<name>.properties
+                  # pairs with secret-<name>.properties
+                  backend="${filename#backend-}"
+                  backend="${backend%.properties}"
+                  backend_secret="/secret/secret-${backend}.properties"
+                  if [ -f "$backend_secret" ]
+                  then
+                    echo "" >> "$output_file"  # Add newline separator
+                    cat "$backend_secret" >> "$output_file"
                   fi
                 fi
               done

@github-actions

Copy link
Copy Markdown

📝 README.md Preview

The following changes to README.md will be applied when this PR is merged:

Click to expand diff
diff --git a/README.md b/README.md
index bf652df..dfcde1c 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>""</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.azureblob.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.azureblob.enabled</code></td>
 			<td>Enable Azure Blob Storage backend</td>
@@ -188,6 +194,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>""</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.b2.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.b2.enabled</code></td>
 			<td>Enable Backblaze B2 backend</td>
@@ -200,6 +212,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>"/data/s3proxy"</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.filesystem.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.filesystem.credential</code></td>
 			<td>jclouds credential. S3Proxy requires jclouds.credential in every backend properties file; the filesystem backend ignores the value. An empty value falls back to "local".</td>
@@ -224,6 +242,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>bool</code></td>
 			<td><code>true</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.googleCloudStorage.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.googleCloudStorage.clientEmail</code></td>
 			<td>Service account email or user email</td>
@@ -272,6 +296,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>""</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.openstackSwift.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.openstackSwift.enabled</code></td>
 			<td>Enable OpenStack Swift backend</td>
@@ -344,6 +374,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>""</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.rackspaceCloudfiles.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.rackspaceCloudfiles.enabled</code></td>
 			<td>Enable Rackspace Cloud Files backend</td>
@@ -374,6 +410,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>bool</code></td>
 			<td><code>true</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.s3.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.s3.enabled</code></td>
 			<td>Enable S3 backend</td>
@@ -416,6 +458,12 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>string</code></td>
 			<td><code>""</code></td>
 		</tr>
+		<tr>
+			<td><code>config.backends.transient.bucketLocators</code></td>
+			<td>Buckets routed to this backend (S3Proxy bucket-locator; glob patterns supported). Only relevant when multiple backends are enabled; a bucket matching no backend's list falls through to the first-enabled backend.</td>
+			<td><code>list</code></td>
+			<td><code>[]</code></td>
+		</tr>
 		<tr>
 			<td><code>config.backends.transient.credential</code></td>
 			<td>jclouds credential. S3Proxy requires jclouds.credential in every backend properties file; the transient backend ignores the value. An empty value falls back to "local".</td>
@@ -446,12 +494,6 @@ The following section lists the configurable parameters of the s3proxy chart and
 			<td><code>object</code></td>
 			<td><code>{}</code></td>
 		</tr>
-		<tr>
-			<td><code>config.buckets.locator</code></td>
-			<td>Assign specific buckets to different backends (glob patterns supported)</td>
-			<td><code>list</code></td>
-			<td><code>[]</code></td>
-		</tr>
 		<tr>
 			<td><code>config.cors.allowCredential</code></td>
 			<td>Allow credentials</td>
@@ -937,17 +979,27 @@ config:
       another-bucket: "actual-bucket-name"
 ```
 
-### Bucket Locator
+### Bucket Locator (routing buckets to backends)
 
-Assign specific buckets to different backends:
+When more than one backend is enabled, assign buckets to a specific backend with
+that backend's own `bucketLocators` list. S3Proxy reads bucket-locators per
+backend, so each list is emitted only into that backend's properties file. Glob
+patterns are supported. A bucket that matches no backend's list falls through to
+the first-enabled backend (the default).
 
 ```yaml
 config:
-  buckets:
-    locator:
-      - "bucket1"
-      - "bucket2"
-      - "*.test"  # Glob patterns supported
+  backends:
+    s3:
+      enabled: true
+      # ... credentials ...
+      bucketLocators:
+        - "prod-*"
+        - "customer-data"
+    filesystem:
+      enabled: true
+      bucketLocators:
+        - "scratch-*"   # everything else also lands here (first-enabled default)
 ```
 
 ## Monitoring

Note: This is an automated preview generated by helm-docs. The changes will be automatically applied upon merge.

@CRThaze
CRThaze merged commit 9b82335 into main Jul 21, 2026
17 of 18 checks passed
CRThaze added a commit that referenced this pull request Jul 21, 2026
Reconciles the chart changes that merged without a version bump (DND-1442 #21,
azureblob endpoint + multi-backend routing #22) together with this PR's HPA
autoscaling/v2 fix, the helm-polish template cleanup, and the added LICENSE.
Clears the verify-version gate and cuts a 0.1.0 release on merge (minor bump:
new azureblob regions value + bucketLocators, no breaking changes).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant