Merge pull request #2296 from versity/sis/iam-helm

feat: add Helm chart support for the standalone IAM service
This commit is contained in:
Ben McClelland
2026-08-26 15:14:35 -07:00
committed by GitHub
12 changed files with 967 additions and 24 deletions
+20
View File
@@ -15,3 +15,23 @@ jobs:
- name: Lint chart
run: helm lint chart/ --strict --set auth.accessKey=dummy --set auth.secretKey=dummy
- name: Lint standalone IAM configurations
run: |
scenarios=(
# existingSecret-based mTLS for both sides, plus NetworkPolicy
"--set iam.enabled=true --set iam.type=standalone --set iam.standalone.certificate.existingSecret=iam-client-tls --set iamServer.enabled=true --set iamServer.private.certificate.existingSecret=iam-server-tls --set networkPolicy.enabled=true"
# cert-manager-issued mTLS, plus TLS on the public control-plane API
"--set iam.enabled=true --set iam.type=standalone --set iam.standalone.certificate.create=true --set iam.standalone.certificate.issuerRef.name=internal-ca --set iamServer.enabled=true --set iamServer.private.certificate.create=true --set iamServer.private.certificate.issuerRef.name=internal-ca --set iamServer.tls.enabled=true --set iamServer.tls.secretName=iam-public-tls"
# Vault storage with multiple iamServer replicas
"--set iamServer.enabled=true --set iamServer.replicaCount=2 --set iamServer.storage.type=vault --set iamServer.storage.vault.endpointUrl=https://vault.example.test --set iamServer.storage.vault.existingSecret=vault-auth --set iamServer.storage.vault.tlsExistingSecret=vault-tls --set iamServer.private.certificate.existingSecret=iam-server-tls"
# externally managed standalone IAM service (no in-chart iamServer)
"--set iam.enabled=true --set iam.type=standalone --set iam.standalone.endpoint=iam.example.test:7443 --set iam.standalone.certificate.existingSecret=iam-client-tls"
)
for scenario in "${scenarios[@]}"; do
echo "::group::helm lint --set ${scenario}"
# shellcheck disable=SC2086
helm lint chart/ --strict --set auth.existingSecret=root-credentials ${scenario}
echo "::endgroup::"
done
+1 -1
View File
@@ -2,7 +2,7 @@ apiVersion: v2
name: versitygw
description: A Helm chart for deploying the Versity S3 Gateway on Kubernetes
type: application
version: 0.3.5
version: 0.4.0
sources:
- https://github.com/versity/versitygw
icon: https://raw.githubusercontent.com/versity/versitygw/main/webui/web/assets/images/Versity-logo-blue-horizontal.png
+43 -3
View File
@@ -12,7 +12,7 @@ Versity is an S3-compatible storage gateway that proxies S3 API requests to a va
- Kubernetes **1.19+**
- Helm **3.8+** (OCI registry support)
- optional: [cert-manager](https://cert-manager.io/) (only required if `certificate.create=true`)
- optional: [cert-manager](https://cert-manager.io/) (required when any of `certificate.create`, `iam.standalone.certificate.create`, or `iamServer.private.certificate.create` is enabled)
## Installation
@@ -104,11 +104,50 @@ gateway:
| **Admin API** | `admin.enabled=true` — exposes a separate management API on `admin.port` (default `7071`) |
| **WebUI** | `webui.enabled=true` — browser-based management UI on `webui.port` (default `8080`); set `webui.apiGateways` and `webui.adminGateways` to your externally reachable endpoints |
| **Website Hosting** | `website.enabled=true` — static website hosting endpoint on `website.port` (default `8090`); optionally set `website.domain` for virtual-host routing (e.g. `example.com`), or omit it for catch-all mode where the full hostname is the bucket name |
| **IAM** | `iam.enabled=true` flat-file identity and access management stored alongside backend data |
| **IAM** | `iam.enabled=true` — identity and access management. `iam.type=internal` (default) stores accounts in a flat file alongside backend data; `iam.type=standalone` delegates to a separate standalone IAM API service — see [Standalone IAM Service](#standalone-iam-service) below |
| **Persistence** | `persistence.enabled=true` — provisions a PVC for backend data and IAM storage; defaults to `10Gi`, or uses a hostPath volume specified by `persistence.hostPath` |
| **NetworkPolicy** | `networkPolicy.enabled=true` — restricts ingress to selected pods/namespaces; allows all egress |
| **Debug logging** | `gateway.logLevel``silent` (default), `debug` (request/response logging, secrets masked), or `unsafe` (unmasked, local troubleshooting only) |
| **Scheduling** | `nodeSelector`, `affinity`, `tolerations`, and `topologySpreadConstraints` — control pod placement and spread replicas across nodes/zones for high availability |
## Standalone IAM Service
In addition to `iam.type=internal` (flat-file IAM stored inside the gateway pod), the chart can deploy the standalone IAM API server — an AWS-compatible IAM Query API — as its own Deployment with separate public and private Services, and configure one or more gateways to use it via `iam.type=standalone`.
```yaml
iam:
enabled: true
type: standalone
standalone:
# Left empty here: auto-targets the in-chart private IAM Service below.
certificate:
create: true
issuerRef:
kind: ClusterIssuer
name: internal-ca
iamServer:
enabled: true
storage:
type: internal # or vault
private:
certificate:
create: true
issuerRef:
kind: ClusterIssuer
name: internal-ca
```
Key points:
- **Independent scaling**: `iamServer` is a separate Deployment (`iamServer.replicaCount`), so it can be centralized and scaled independently of the gateway. Manage users/roles/policies against its public control-plane API (`iamServer.port`, default `7070`) using the AWS CLI/SDK. It reuses the gateway root Secret by default; set `iamServer.auth.existingSecret` to separate the control-plane identity, and point `iam.standalone.credentials.existingSecret` at the corresponding client identity.
- **Storage**: `iamServer.storage.type` is `internal` (file-backed, needs `iamServer.persistence`, is limited to one replica, and always uses a `Recreate` rollout) or `vault` (`iamServer.storage.vault.*`, centralized and required if `iamServer.replicaCount > 1`).
- **Separate Services**: `iamServer.service.type` applies only to the public control-plane Service. The private listener is exposed by a separate, always-`ClusterIP` Service, so selecting `NodePort` or `LoadBalancer` does not publish the private port. Enable `iamServer.tls` before exposing the public API outside a trusted network.
- **Private mTLS endpoint**: gateways reach the standalone IAM service over a private endpoint (`iamServer.private.port`, default `7443`) that always requires mutual TLS on TCP. Provide certificates either via `existingSecret` (bring your own `tls.crt`/`tls.key`/`ca.crt`) or `certificate.create=true` to auto-provision via cert-manager.
- **Shared CA requirement**: when using cert-manager auto-provisioning, `iamServer.private.certificate.issuerRef` and `iam.standalone.certificate.issuerRef` **must reference the same CA-type issuer** (an `Issuer`/`ClusterIssuer` of kind `CA`, or a Vault issuer) — one that populates `ca.crt` in the resulting Secret. Both sides verify their peer using their own certificate's `ca.crt`, which only works when both certificates share the same issuing CA.
- **External IAM service**: to point a gateway at a standalone IAM service deployed outside this chart (or by a separate chart release), set `iam.standalone.endpoint` to its `host:port` and provide the mTLS material via `iam.standalone.certificate.existingSecret`.
- **Secret rotation**: the processes load mTLS material and environment-based credentials at startup. After a referenced Secret rotates, restart both Deployments or configure a Secret-reloader controller through `deploymentAnnotations` and `iamServer.deploymentAnnotations`.
## Scaling and Persistence
By default, this chart enables persistence via a `PersistentVolumeClaim` (PVC) to ensure data consistency and prevent data loss.
@@ -121,9 +160,10 @@ Special care must be taken particularly when using multiple replicas with such a
When scaling `versitygw` horizontally by setting `replicaCount` greater than 1, special care must be taken regarding the storage backend:
- **POSIX or Internal IAM**: These backends store state locally on the filesystem.
- **POSIX**: This backend stores state on the filesystem.
- Using **ReadWriteOnce (RWO)**: All replicas must be scheduled on the **same Kubernetes node** to share the same volume. This is useful for process-level concurrency (e.g., when using high-performance local block storage) but limits high availability across nodes.
- Using **ReadWriteMany (RWX)**: Replicas can be distributed across **multiple nodes** in the cluster. This is the recommended approach for true horizontal scaling and high availability. When using RWX, it is also recommended to use pod anti-affinity (via `affinity` in `values.yaml`) or topology spread constraints (via `topologySpreadConstraints` in `values.yaml`) to ensure pods are distributed across nodes/zones.
- **IAM**: `iam.type=internal` is limited to a single gateway replica because its file store does not coordinate concurrent writers. Use standalone IAM with Vault storage, LDAP, Vault-direct, or another external IAM backend before scaling the gateway above one replica.
- **Stateless Backends (S3, Azure)**: If you are using a stateless storage backend (e.g. proxying to another S3 store) **and** you are either not using IAM or using an external IAM provider (e.g. LDAP, Vault), persistence can be safely disabled by setting `persistence.enabled=false`.
### Deployment Strategy
+119
View File
@@ -73,6 +73,20 @@ Uses auth.existingSecret if set, otherwise derives a name from the release fulln
{{- end }}
{{- end }}
{{/*
The root credential Secret used by the standalone IAM API server. It defaults
to the gateway root Secret for backward compatibility, but can be separated so
the public IAM control plane and S3 gateway do not share administrative keys.
*/}}
{{- define "versitygw.iamServerCredentialsSecretName" -}}
{{- $auth := .Values.iamServer.auth | default dict -}}
{{- if $auth.existingSecret }}
{{- $auth.existingSecret }}
{{- else }}
{{- include "versitygw.credentialsSecretName" . }}
{{- end }}
{{- end }}
{{/*
The name of the PVC to use for persistence.
Returns empty string if persistence is disabled.
@@ -98,3 +112,108 @@ Uses certificate.secretName if set, otherwise derives a name from the release fu
{{- printf "%s-cert" (include "versitygw.fullname" .) }}
{{- end }}
{{- end }}
{{/*
The name label for the standalone IAM API server. It must differ from the
gateway's name label because the gateway Deployment's immutable selector only
contains app.kubernetes.io/name and app.kubernetes.io/instance. Reusing that
pair would make the gateway Deployment, Service, and NetworkPolicy also select
IAM server pods.
*/}}
{{- define "versitygw.iamServerName" -}}
{{- $base := include "versitygw.name" . | trunc 59 | trimSuffix "-" -}}
{{- printf "%s-iam" $base }}
{{- end }}
{{/*
The fullname of the standalone IAM API server's Deployment/Service.
*/}}
{{- define "versitygw.iamServerFullname" -}}
{{- $base := include "versitygw.fullname" . | trunc 59 | trimSuffix "-" -}}
{{- printf "%s-iam" $base }}
{{- end }}
{{/*
The standalone IAM private Service is always cluster-internal, independently
of how the public control-plane Service is exposed.
*/}}
{{- define "versitygw.iamServerPrivateServiceFullname" -}}
{{- $base := include "versitygw.fullname" . | trunc 51 | trimSuffix "-" -}}
{{- printf "%s-iam-private" $base }}
{{- end }}
{{/*
Selector labels for the standalone IAM API server. Deliberately separate from
versitygw.selectorLabels (used by the main gateway Deployment's immutable
spec.selector) so the two Deployments never collide.
*/}}
{{- define "versitygw.iamServerSelectorLabels" -}}
app.kubernetes.io/name: {{ include "versitygw.iamServerName" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: iam-server
{{- end }}
{{/*
Common labels for the standalone IAM API server.
*/}}
{{- define "versitygw.iamServerLabels" -}}
helm.sh/chart: {{ include "versitygw.chart" . }}
{{ include "versitygw.iamServerSelectorLabels" . }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
The name of the PVC used for the standalone IAM API server's file-backed storage.
Returns empty string if persistence is disabled.
*/}}
{{- define "versitygw.iamServerPvcName" -}}
{{- if .Values.iamServer.persistence.enabled }}
{{- if .Values.iamServer.persistence.claimName }}
{{- .Values.iamServer.persistence.claimName }}
{{- else }}
{{- $base := include "versitygw.fullname" . | trunc 54 | trimSuffix "-" -}}
{{- printf "%s-iam-data" $base }}
{{- end }}
{{- end }}
{{- end }}
{{/*
The name of the Secret holding the standalone IAM API server's private-listener
server certificate (tls.crt/tls.key) and the CA (ca.crt) used to verify gateway
client certificates. Uses iamServer.private.certificate.existingSecret if set,
otherwise derives a name for the cert-manager-managed Certificate.
*/}}
{{- define "versitygw.iamServerPrivateCertSecretName" -}}
{{- if .Values.iamServer.private.certificate.existingSecret }}
{{- .Values.iamServer.private.certificate.existingSecret }}
{{- else }}
{{- printf "%s-private-cert" (include "versitygw.iamServerFullname" .) }}
{{- end }}
{{- end }}
{{/*
The name of the Secret holding the gateway's mTLS client certificate
(tls.crt/tls.key) and the CA (ca.crt) used to verify the standalone IAM
service's server certificate. Uses iam.standalone.certificate.existingSecret
if set, otherwise derives a name for the cert-manager-managed Certificate.
*/}}
{{- define "versitygw.iamClientCertSecretName" -}}
{{- if .Values.iam.standalone.certificate.existingSecret }}
{{- .Values.iam.standalone.certificate.existingSecret }}
{{- else }}
{{- printf "%s-iam-client-cert" (include "versitygw.fullname" .) }}
{{- end }}
{{- end }}
{{/*
The gateway's standalone-IAM private endpoint address. Uses
iam.standalone.endpoint if set, otherwise auto-targets the in-chart iamServer
Service's private port.
*/}}
{{- define "versitygw.standaloneIAMEndpoint" -}}
{{- if .Values.iam.standalone.endpoint }}
{{- .Values.iam.standalone.endpoint }}
{{- else if .Values.iamServer.enabled }}
{{- printf "%s:%d" (include "versitygw.iamServerPrivateServiceFullname" .) (.Values.iamServer.private.port | int) }}
{{- end }}
{{- end }}
+103 -3
View File
@@ -1,7 +1,19 @@
{{- $gatewayLogLevel := default "silent" .Values.gateway.logLevel -}}
{{- $iamServer := .Values.iamServer | default dict -}}
{{- $iamServerEnabled := $iamServer.enabled | default false -}}
{{- $iamServerPrivate := $iamServer.private | default dict -}}
{{- $iamServerPrivateEnabled := $iamServerPrivate.enabled | default false -}}
{{- $iamServerAuth := $iamServer.auth | default dict -}}
{{- $iamStandalone := .Values.iam.standalone | default dict -}}
{{- $iamStandaloneEndpoint := $iamStandalone.endpoint | default "" -}}
{{- $iamStandaloneCredentials := $iamStandalone.credentials | default dict -}}
{{- /* Safety check: multiple replicas with local state must have persistence enabled */}}
{{- if and (gt (int .Values.replicaCount) 1) .Values.iam.enabled (eq .Values.iam.type "internal") }}
{{- fail "replicaCount > 1 cannot use iam.type=internal because the file store does not coordinate concurrent writers; use standalone or another external IAM backend" }}
{{- end }}
{{- if and (gt (int .Values.replicaCount) 1) (not .Values.persistence.enabled) }}
{{- if or (eq .Values.gateway.backend.type "posix") (and .Values.iam.enabled (eq .Values.iam.type "internal")) }}
{{- fail "Multiple replicas with POSIX backend or Internal IAM require persistence.enabled=true to prevent data loss and inconsistency across pods. If using a stateless backend (e.g. S3, Azure) and external IAM, set persistence.enabled=false." }}
{{- if eq .Values.gateway.backend.type "posix" }}
{{- fail "Multiple replicas with a POSIX backend require persistence.enabled=true. If using a stateless backend (e.g. S3 or Azure) and external IAM, persistence can be disabled." }}
{{- end }}
{{- end }}
{{- if and .Values.persistence.enabled (not .Values.persistence.create) (not .Values.persistence.claimName) (not .Values.persistence.hostPath) }}
@@ -19,12 +31,46 @@
{{- if and .Values.gateway.backend.versioningDir (not (or (eq .Values.gateway.backend.type "posix") (eq .Values.gateway.backend.type "scoutfs"))) }}
{{- fail "gateway.backend.versioningDir is only supported with the posix and scoutfs backends" }}
{{- end }}
{{- if not (or (eq $gatewayLogLevel "silent") (eq $gatewayLogLevel "debug") (eq $gatewayLogLevel "unsafe")) }}
{{- fail "gateway.logLevel must be one of silent, debug, or unsafe" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (not .Values.iam.standalone.endpoint) (not $iamServerEnabled) }}
{{- fail "iam.type=standalone requires either iam.standalone.endpoint or iamServer.enabled=true" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (not .Values.iam.standalone.endpoint) $iamServerEnabled (not $iamServerPrivateEnabled) }}
{{- fail "in-chart standalone IAM requires iamServer.private.enabled=true; otherwise set iam.standalone.endpoint explicitly" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") $iamStandaloneEndpoint (not (regexMatch "^(\\[[0-9A-Fa-f:]+\\]|[^/:[:space:]]+):[0-9]+$" $iamStandaloneEndpoint)) }}
{{- fail "iam.standalone.endpoint must be a host:port TCP address; the chart does not provide a shared volume for Unix sockets" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (not (or .Values.iam.standalone.certificate.create .Values.iam.standalone.certificate.existingSecret)) }}
{{- fail "a standalone IAM TCP endpoint requires iam.standalone.certificate.create=true or iam.standalone.certificate.existingSecret" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") .Values.iam.standalone.certificate.create (not .Values.iam.standalone.certificate.existingSecret) (not .Values.iam.standalone.certificate.issuerRef.name) }}
{{- fail "iam.standalone.certificate.issuerRef.name is required when creating the IAM client certificate" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (or (and .Values.iam.standalone.access (not .Values.iam.standalone.secret)) (and .Values.iam.standalone.secret (not .Values.iam.standalone.access))) }}
{{- fail "iam.standalone.access and iam.standalone.secret must be set together, or both left empty to use the root credentials" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") $iamStandaloneCredentials.existingSecret (or .Values.iam.standalone.access .Values.iam.standalone.secret) }}
{{- fail "iam.standalone.credentials.existingSecret cannot be combined with literal iam.standalone.access/secret values" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") $iamStandaloneCredentials.existingSecret (or (not $iamStandaloneCredentials.accessKeyKey) (not $iamStandaloneCredentials.secretKeyKey)) }}
{{- fail "iam.standalone.credentials.accessKeyKey and secretKeyKey are required when credentials.existingSecret is set" }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (not .Values.iam.standalone.endpoint) $iamServerAuth.existingSecret (not $iamStandaloneCredentials.existingSecret) (not .Values.iam.standalone.access) }}
{{- fail "in-chart IAM with iamServer.auth.existingSecret requires iam.standalone.credentials.existingSecret (normally the same Secret)" }}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "versitygw.fullname" . }}
labels:
{{- include "versitygw.labels" . | nindent 4 }}
{{- with .Values.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
@@ -105,7 +151,10 @@ spec:
- name: VGW_QUIET
value: "true"
{{- end }}
{{- if .Values.gateway.debug }}
{{- if ne $gatewayLogLevel "silent" }}
- name: VGW_LOG_LEVEL
value: {{ $gatewayLogLevel | quote }}
{{- else if .Values.gateway.debug }}
- name: VGW_LOG_LEVEL
value: "debug"
{{- end }}
@@ -163,6 +212,44 @@ spec:
{{- if eq .Values.iam.type "internal" }}
- name: VGW_IAM_DIR
value: "/mnt/iam"
{{- else if eq .Values.iam.type "standalone" }}
- name: VGW_IAM_STANDALONE_ENDPOINT
value: {{ include "versitygw.standaloneIAMEndpoint" . | quote }}
{{- if $iamStandaloneCredentials.existingSecret }}
- name: VGW_IAM_STANDALONE_ACCESS
valueFrom:
secretKeyRef:
name: {{ $iamStandaloneCredentials.existingSecret }}
key: {{ $iamStandaloneCredentials.accessKeyKey }}
- name: VGW_IAM_STANDALONE_SECRET
valueFrom:
secretKeyRef:
name: {{ $iamStandaloneCredentials.existingSecret }}
key: {{ $iamStandaloneCredentials.secretKeyKey }}
{{- else }}
{{- if .Values.iam.standalone.access }}
- name: VGW_IAM_STANDALONE_ACCESS
value: {{ .Values.iam.standalone.access | quote }}
{{- end }}
{{- if .Values.iam.standalone.secret }}
- name: VGW_IAM_STANDALONE_SECRET
value: {{ .Values.iam.standalone.secret | quote }}
{{- end }}
{{- end }}
{{- if or .Values.iam.standalone.certificate.create .Values.iam.standalone.certificate.existingSecret }}
- name: VGW_IAM_STANDALONE_CLIENT_CERT
value: /iam-client-certs/tls.crt
- name: VGW_IAM_STANDALONE_CLIENT_CERT_KEY
value: /iam-client-certs/tls.key
- name: VGW_IAM_STANDALONE_SERVER_CA
value: /iam-client-certs/ca.crt
{{- end }}
- name: VGW_IAM_STANDALONE_DEFAULT_UID
value: {{ .Values.iam.standalone.defaultUid | quote }}
- name: VGW_IAM_STANDALONE_DEFAULT_GID
value: {{ .Values.iam.standalone.defaultGid | quote }}
- name: VGW_IAM_STANDALONE_DEFAULT_PROJECT_ID
value: {{ .Values.iam.standalone.defaultProjectId | quote }}
{{- end }}
{{- if .Values.iam.cacheDisable }}
- name: VGW_IAM_CACHE_DISABLE
@@ -235,10 +322,17 @@ spec:
subPath: versioning
readOnly: false
{{- end }}
{{- if or (not .Values.iam.enabled) (eq .Values.iam.type "internal") }}
- name: data
mountPath: /mnt/iam
subPath: iam
readOnly: false
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (or .Values.iam.standalone.certificate.create .Values.iam.standalone.certificate.existingSecret) }}
- name: iam-client-certs
mountPath: /iam-client-certs
readOnly: true
{{- end }}
{{- if .Values.tls.enabled }}
- name: certificates
mountPath: /certs
@@ -263,6 +357,12 @@ spec:
secret:
secretName: {{ include "versitygw.certificateSecretName" . }}
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") (or .Values.iam.standalone.certificate.create .Values.iam.standalone.certificate.existingSecret) }}
- name: iam-client-certs
secret:
secretName: {{ include "versitygw.iamClientCertSecretName" . }}
defaultMode: 0440
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
+45
View File
@@ -0,0 +1,45 @@
{{- $iamServer := .Values.iamServer | default dict -}}
{{- if and ($iamServer.enabled | default false) .Values.iamServer.private.enabled .Values.iamServer.private.certificate.create (not .Values.iamServer.private.certificate.existingSecret) }}
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "versitygw.iamServerPrivateCertSecretName" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
spec:
dnsNames:
{{- if .Values.iamServer.private.certificate.dnsNames }}
{{- toYaml .Values.iamServer.private.certificate.dnsNames | nindent 4 }}
{{- else }}
- {{ include "versitygw.iamServerPrivateServiceFullname" . }}
- {{ printf "%s.%s.svc" (include "versitygw.iamServerPrivateServiceFullname" .) .Release.Namespace }}
- {{ printf "%s.%s.svc.cluster.local" (include "versitygw.iamServerPrivateServiceFullname" .) .Release.Namespace }}
{{- end }}
issuerRef:
{{- toYaml .Values.iamServer.private.certificate.issuerRef | nindent 4 }}
privateKey:
algorithm: ECDSA
size: 256
secretName: {{ include "versitygw.iamServerPrivateCertSecretName" . }}
usages:
- server auth
{{- end }}
{{- if and .Values.iam.enabled (eq .Values.iam.type "standalone") .Values.iam.standalone.certificate.create (not .Values.iam.standalone.certificate.existingSecret) }}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ include "versitygw.iamClientCertSecretName" . }}
labels:
{{- include "versitygw.labels" . | nindent 4 }}
spec:
commonName: {{ include "versitygw.fullname" . }}
issuerRef:
{{- toYaml .Values.iam.standalone.certificate.issuerRef | nindent 4 }}
privateKey:
algorithm: ECDSA
size: 256
secretName: {{ include "versitygw.iamClientCertSecretName" . }}
usages:
- client auth
{{- end }}
+300
View File
@@ -0,0 +1,300 @@
{{- $iamServer := .Values.iamServer | default dict -}}
{{- if ($iamServer.enabled | default false) }}
{{- $iamServerAuth := .Values.iamServer.auth | default dict -}}
{{- if not (or (eq .Values.iamServer.storage.type "internal") (eq .Values.iamServer.storage.type "vault")) }}
{{- fail "iamServer.storage.type must be either internal or vault" }}
{{- end }}
{{- if and (gt (int .Values.iamServer.replicaCount) 1) (eq .Values.iamServer.storage.type "internal") }}
{{- fail "iamServer.replicaCount > 1 requires iamServer.storage.type=vault; the internal file store does not coordinate concurrent writers" }}
{{- end }}
{{- if and (eq .Values.iamServer.storage.type "internal") .Values.iamServer.persistence.enabled (not .Values.iamServer.persistence.create) (not .Values.iamServer.persistence.claimName) }}
{{- fail "iamServer.persistence.claimName is required when iamServer.persistence.create is false" }}
{{- end }}
{{- if and (eq .Values.iamServer.storage.type "vault") (not .Values.iamServer.storage.vault.endpointUrl) }}
{{- fail "iamServer.storage.vault.endpointUrl is required when iamServer.storage.type=vault" }}
{{- end }}
{{- if and .Values.iamServer.private.enabled (not .Values.iamServer.private.certificate.create) (not .Values.iamServer.private.certificate.existingSecret) }}
{{- fail "iamServer.private.enabled requires either iamServer.private.certificate.create=true or iamServer.private.certificate.existingSecret" }}
{{- end }}
{{- if and .Values.iamServer.private.enabled .Values.iamServer.private.certificate.create (not .Values.iamServer.private.certificate.existingSecret) (not .Values.iamServer.private.certificate.issuerRef.name) }}
{{- fail "iamServer.private.certificate.issuerRef.name is required when creating the IAM server certificate" }}
{{- end }}
{{- if and .Values.iamServer.private.enabled (eq (int .Values.iamServer.private.port) (int .Values.iamServer.port)) }}
{{- fail "iamServer.private.port must differ from iamServer.port" }}
{{- end }}
{{- if and .Values.iamServer.tls.enabled (not .Values.iamServer.tls.secretName) }}
{{- fail "iamServer.tls.secretName is required when iamServer.tls.enabled=true" }}
{{- end }}
{{- if not (or (eq .Values.iamServer.logLevel "silent") (eq .Values.iamServer.logLevel "debug") (eq .Values.iamServer.logLevel "unsafe")) }}
{{- fail "iamServer.logLevel must be one of silent, debug, or unsafe" }}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "versitygw.iamServerFullname" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
{{- with .Values.iamServer.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.iamServer.replicaCount }}
selector:
matchLabels:
{{- include "versitygw.iamServerSelectorLabels" . | nindent 6 }}
{{- if eq .Values.iamServer.storage.type "internal" }}
# Avoid overlapping file-store writers and ReadWriteOnce multi-attach errors
# while a new ReplicaSet replaces the old one.
strategy:
type: Recreate
{{- else }}
{{- with .Values.iamServer.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
template:
metadata:
annotations:
{{- if and (not $iamServerAuth.existingSecret) (not .Values.auth.existingSecret) }}
checksum/credentials: {{ cat .Release.Name .Values.auth.accessKey .Values.auth.secretKey | sha256sum | trunc 12 }}
{{- end }}
{{- with .Values.iamServer.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "versitygw.iamServerSelectorLabels" . | nindent 8 }}
{{- with .Values.iamServer.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "versitygw.serviceAccountName" . }}
automountServiceAccountToken: false
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: iam-server
image: "{{ .Values.iamServer.image.repository | default .Values.image.repository }}:{{ .Values.iamServer.image.tag | default .Values.image.tag }}"
imagePullPolicy: {{ .Values.iamServer.image.pullPolicy | default .Values.image.pullPolicy }}
env:
- name: VGW_BACKEND
value: "iam"
# Root credentials -- sourced from the same Kubernetes Secret as the gateway
- name: ROOT_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ include "versitygw.iamServerCredentialsSecretName" . }}
key: rootAccessKeyId
- name: ROOT_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ include "versitygw.iamServerCredentialsSecretName" . }}
key: rootSecretAccessKey
- name: VGW_PORT
value: ":{{ .Values.iamServer.port }}"
- name: VGW_HEALTH
value: "/_/health"
- name: VGW_MAX_CONNECTIONS
value: {{ .Values.iamServer.maxConnections | quote }}
- name: VGW_MAX_REQUESTS
value: {{ .Values.iamServer.maxRequests | quote }}
{{- if .Values.iamServer.quiet }}
- name: VGW_QUIET
value: "true"
{{- end }}
{{- if ne .Values.iamServer.logLevel "silent" }}
- name: VGW_LOG_LEVEL
value: {{ .Values.iamServer.logLevel | quote }}
{{- end }}
{{- if .Values.iamServer.disableOidcThumbprintAutofetch }}
- name: VGW_IAM_DISABLE_OIDC_THUMBPRINT_AUTOFETCH
value: "true"
{{- end }}
{{- if .Values.iamServer.tls.enabled }}
- name: VGW_CERT
value: /certs/tls.crt
- name: VGW_KEY
value: /certs/tls.key
{{- end }}
# Storage backend
{{- if eq .Values.iamServer.storage.type "internal" }}
- name: VGW_IAM_DIR
value: "/mnt/iam"
{{- else if eq .Values.iamServer.storage.type "vault" }}
- name: VGW_IAM_VAULT_ENDPOINT_URL
value: {{ .Values.iamServer.storage.vault.endpointUrl | quote }}
{{- if .Values.iamServer.storage.vault.namespace }}
- name: VGW_IAM_VAULT_NAMESPACE
value: {{ .Values.iamServer.storage.vault.namespace | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.secretStoragePath }}
- name: VGW_IAM_VAULT_SECRET_STORAGE_PATH
value: {{ .Values.iamServer.storage.vault.secretStoragePath | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.secretStorageNamespace }}
- name: VGW_IAM_VAULT_SECRET_STORAGE_NAMESPACE
value: {{ .Values.iamServer.storage.vault.secretStorageNamespace | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.authMethod }}
- name: VGW_IAM_VAULT_AUTH_METHOD
value: {{ .Values.iamServer.storage.vault.authMethod | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.authNamespace }}
- name: VGW_IAM_VAULT_AUTH_NAMESPACE
value: {{ .Values.iamServer.storage.vault.authNamespace | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.mountPath }}
- name: VGW_IAM_VAULT_MOUNT_PATH
value: {{ .Values.iamServer.storage.vault.mountPath | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.roleId }}
- name: VGW_IAM_VAULT_ROLE_ID
value: {{ .Values.iamServer.storage.vault.roleId | quote }}
{{- end }}
{{- if .Values.iamServer.storage.vault.existingSecret }}
- name: VGW_IAM_VAULT_ROLE_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.iamServer.storage.vault.existingSecret }}
key: roleSecret
optional: true
- name: VGW_IAM_VAULT_ROOT_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Values.iamServer.storage.vault.existingSecret }}
key: rootToken
optional: true
{{- end }}
{{- if .Values.iamServer.storage.vault.tlsExistingSecret }}
{{- if not .Values.iamServer.storage.vault.serverCert }}
- name: VGW_IAM_VAULT_SERVER_CERT
valueFrom:
secretKeyRef:
name: {{ .Values.iamServer.storage.vault.tlsExistingSecret }}
key: serverCert
optional: true
{{- end }}
{{- if not .Values.iamServer.storage.vault.clientCert }}
- name: VGW_IAM_VAULT_CLIENT_CERT
valueFrom:
secretKeyRef:
name: {{ .Values.iamServer.storage.vault.tlsExistingSecret }}
key: clientCert
optional: true
{{- end }}
{{- if not .Values.iamServer.storage.vault.clientCertKey }}
- name: VGW_IAM_VAULT_CLIENT_CERT_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.iamServer.storage.vault.tlsExistingSecret }}
key: clientCertKey
optional: true
{{- end }}
{{- end }}
{{- if .Values.iamServer.storage.vault.serverCert }}
- name: VGW_IAM_VAULT_SERVER_CERT
value: |
{{- .Values.iamServer.storage.vault.serverCert | nindent 16 }}
{{- end }}
{{- if .Values.iamServer.storage.vault.clientCert }}
- name: VGW_IAM_VAULT_CLIENT_CERT
value: |
{{- .Values.iamServer.storage.vault.clientCert | nindent 16 }}
{{- end }}
{{- if .Values.iamServer.storage.vault.clientCertKey }}
- name: VGW_IAM_VAULT_CLIENT_CERT_KEY
value: |
{{- .Values.iamServer.storage.vault.clientCertKey | nindent 16 }}
{{- end }}
{{- end }}
# Private mTLS endpoint
{{- if .Values.iamServer.private.enabled }}
- name: VGW_IAM_PRIVATE_PORTS
value: ":{{ .Values.iamServer.private.port }}"
- name: VGW_IAM_PRIVATE_CERT
value: /iam-private-certs/tls.crt
- name: VGW_IAM_PRIVATE_CERT_KEY
value: /iam-private-certs/tls.key
- name: VGW_IAM_PRIVATE_CLIENT_CA
value: /iam-private-certs/ca.crt
{{- end }}
ports:
- name: iam-api
containerPort: {{ .Values.iamServer.port }}
protocol: TCP
{{- if .Values.iamServer.private.enabled }}
- name: iam-private
containerPort: {{ .Values.iamServer.private.port }}
protocol: TCP
{{- end }}
readinessProbe:
httpGet:
path: "/_/health"
port: iam-api
{{- if .Values.iamServer.tls.enabled }}
scheme: HTTPS
{{- end }}
initialDelaySeconds: 5
periodSeconds: 15
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
resources:
{{- toYaml .Values.iamServer.resources | nindent 12 }}
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
{{- if eq .Values.iamServer.storage.type "internal" }}
- name: data
mountPath: /mnt/iam
readOnly: false
{{- end }}
{{- if .Values.iamServer.private.enabled }}
- name: private-certs
mountPath: /iam-private-certs
readOnly: true
{{- end }}
{{- if .Values.iamServer.tls.enabled }}
- name: certificates
mountPath: /certs
readOnly: true
{{- end }}
volumes:
{{- if eq .Values.iamServer.storage.type "internal" }}
- name: data
{{- if .Values.iamServer.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ include "versitygw.iamServerPvcName" . }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
{{- if .Values.iamServer.private.enabled }}
- name: private-certs
secret:
secretName: {{ include "versitygw.iamServerPrivateCertSecretName" . }}
defaultMode: 0440
{{- end }}
{{- if .Values.iamServer.tls.enabled }}
- name: certificates
secret:
secretName: {{ .Values.iamServer.tls.secretName }}
defaultMode: 0440
{{- end }}
{{- with .Values.iamServer.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.iamServer.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.iamServer.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
+18
View File
@@ -0,0 +1,18 @@
{{- $iamServer := .Values.iamServer | default dict -}}
{{- if and ($iamServer.enabled | default false) (eq .Values.iamServer.storage.type "internal") .Values.iamServer.persistence.enabled .Values.iamServer.persistence.create -}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "versitygw.iamServerPvcName" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.iamServer.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.iamServer.persistence.size }}
{{- if .Values.iamServer.persistence.storageClassName }}
storageClassName: {{ .Values.iamServer.persistence.storageClassName | quote }}
{{- end }}
{{- end }}
+36
View File
@@ -0,0 +1,36 @@
{{- $iamServer := .Values.iamServer | default dict -}}
{{- if ($iamServer.enabled | default false) }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "versitygw.iamServerFullname" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
spec:
type: {{ .Values.iamServer.service.type }}
ports:
- port: {{ .Values.iamServer.port }}
targetPort: iam-api
protocol: TCP
name: iam-api
selector:
{{- include "versitygw.iamServerSelectorLabels" . | nindent 4 }}
{{- if .Values.iamServer.private.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "versitygw.iamServerPrivateServiceFullname" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
spec:
type: ClusterIP
ports:
- port: {{ .Values.iamServer.private.port }}
targetPort: iam-private
protocol: TCP
name: iam-private
selector:
{{- include "versitygw.iamServerSelectorLabels" . | nindent 4 }}
{{- end }}
{{- end }}
+82 -4
View File
@@ -1,20 +1,98 @@
{{- $allowedNamespaces := .Values.networkPolicy.allowIngressFromNamespaces | default dict -}}
{{- $allowedPods := .Values.networkPolicy.allowIngressFromPods | default dict -}}
{{- $iamServer := .Values.iamServer | default dict -}}
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "versitygw.fullname" . }}
labels:
{{- include "versitygw.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "versitygw.selectorLabels" . | nindent 6 }}
# Permit ingress traffic only from the specified namespaces and pods
ingress:
{{- if and $allowedNamespaces $allowedPods }}
- from:
namespaceSelector:
matchLabels: {{- toYaml .Values.networkPolicy.allowIngressFromNamespaces | nindent 10 }}
podSelector: {{- toYaml .Values.networkPolicy.allowIngressFromPods | nindent 10 }}
# By omitting the ports specification we apply this NetworkPolicy to all ports
- namespaceSelector:
matchLabels:
{{- toYaml $allowedNamespaces | nindent 14 }}
podSelector:
matchLabels:
{{- toYaml $allowedPods | nindent 14 }}
ports: []
{{- else if $allowedNamespaces }}
- from:
- namespaceSelector:
matchLabels:
{{- toYaml $allowedNamespaces | nindent 14 }}
ports: []
{{- else if $allowedPods }}
- from:
- podSelector:
matchLabels:
{{- toYaml $allowedPods | nindent 14 }}
ports: []
{{- else }}
[]
{{- end }}
# All egress traffic is allowed
egress:
- {}
policyTypes:
- Ingress
- Egress
{{- end }}
{{- if and .Values.networkPolicy.enabled ($iamServer.enabled | default false) }}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "versitygw.iamServerFullname" . }}
labels:
{{- include "versitygw.iamServerLabels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "versitygw.iamServerSelectorLabels" . | nindent 6 }}
# The in-chart gateway must always be able to reach the private IAM port.
# The configured peer selectors additionally control access to all IAM ports.
ingress:
{{- if .Values.iamServer.private.enabled }}
- from:
- podSelector:
matchLabels:
{{- include "versitygw.selectorLabels" . | nindent 14 }}
ports:
- protocol: TCP
port: iam-private
{{- end }}
{{- if and $allowedNamespaces $allowedPods }}
- from:
- namespaceSelector:
matchLabels:
{{- toYaml $allowedNamespaces | nindent 14 }}
podSelector:
matchLabels:
{{- toYaml $allowedPods | nindent 14 }}
ports: []
{{- else if $allowedNamespaces }}
- from:
- namespaceSelector:
matchLabels:
{{- toYaml $allowedNamespaces | nindent 14 }}
ports: []
{{- else if $allowedPods }}
- from:
- podSelector:
matchLabels:
{{- toYaml $allowedPods | nindent 14 }}
ports: []
{{- else if not .Values.iamServer.private.enabled }}
[]
{{- end }}
# All egress traffic is allowed
egress:
- {}
+198 -11
View File
@@ -34,6 +34,9 @@ serviceAccount:
# Additional annotations for the pod
podAnnotations: {}
# Additional annotations for the Deployment object (for example, a Secret
# reloader controller that restarts pods after credential/certificate rotation).
deploymentAnnotations: {}
# Additional labels for the pod
podLabels: {}
@@ -42,8 +45,11 @@ podLabels: {}
# For more details refer to https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
podSecurityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
@@ -159,7 +165,14 @@ gateway:
readOnly: false
# Silence stdout request logging (useful when using a dedicated access log).
quiet: false
# Enable verbose debug output.
# Debug logger verbosity: "silent" (default, no debug output), "debug" (full
# request/response logging with secrets and tokens masked), or "unsafe"
# (full logging with NO masking -- prints access keys, secrets, session
# tokens, and signatures in the clear; only use for local troubleshooting,
# never in production).
logLevel: silent
# Deprecated: use logLevel: debug instead. Kept for backwards compatibility;
# only takes effect when logLevel is left at "silent".
debug: false
# Access log file path for S3 requests (AWS log format). Empty = disabled.
accessLog: ""
@@ -287,11 +300,17 @@ website:
# Disable TLS for the website endpoint even when gateway TLS is enabled.
noTls: false
# --- IAM (Identity and Access Management) ---
# --- IAM (Identity and Access Management) client, consumed by the S3 gateway ---
iam:
enabled: false
# TODO: implement other IAM backend
# Internal flat-file IAM is the default. For production, consider LDAP or Vault.
# TODO: implement other IAM backend (LDAP, Vault-direct, FreeIPA)
# - internal: flat-file IAM stored alongside backend data, inside the gateway pod.
# - standalone: delegate to a separate standalone IAM API service (an
# AWS-compatible IAM Query API server), reached over its private mTLS
# endpoint. See `iamServer` below to optionally deploy that service from
# this same chart, or point `iam.standalone.endpoint` at an externally
# managed one.
# Other values remain available for IAM backends configured through extraEnv.
type: internal
# Disable IAM result caching.
cacheDisable: false
@@ -299,9 +318,175 @@ iam:
cacheTtl: 120
# IAM cache cleanup interval in seconds.
cachePrune: 3600
# Enable debug output for IAM operations.
# Enable IAM-specific debug output (independent of gateway.logLevel).
debug: false
# --- standalone (iam.type: standalone) ---
standalone:
# Private endpoint of the standalone IAM service: a "host:port" TCP
# address (mTLS required -- see `certificate` below). Leave empty to
# auto-target the in-chart private `iamServer` Service
# (requires iamServer.enabled=true and iamServer.private.enabled=true).
endpoint: ""
# Identity this gateway signs its private-endpoint calls with. Both
# default to auth.accessKey/secretKey (root) when left empty. Literal
# values are retained for compatibility but are stored in Helm release
# history; prefer credentials.existingSecret for production.
access: ""
secret: ""
credentials:
# Optional Secret containing a distinct IAM client identity. Point this
# at iamServer.auth.existingSecret to use that server's root identity.
existingSecret: ""
accessKeyKey: rootAccessKeyId
secretKeyKey: rootSecretAccessKey
# POSIX uid/gid/project-id assigned to every account resolved through
# this backend (the standalone IAM service has no per-user POSIX
# identity concept of its own).
defaultUid: 0
defaultGid: 0
defaultProjectId: 0
# mTLS client identity presented to the standalone IAM service's private
# endpoint. Required together with the peer trusting this certificate.
certificate:
# Auto-provision this client certificate via cert-manager. issuerRef
# must be a CA-type issuer (Issuer/ClusterIssuer of kind CA, or Vault) --
# one that populates ca.crt in the resulting Secret -- and MUST be the
# same issuer used for iamServer.private.certificate, so each side's
# ca.crt can verify the other's certificate.
create: false
# Use an existing Secret instead (or as well as -- existingSecret wins
# when both are set). Must contain tls.crt, tls.key, and ca.crt (the CA
# that signed iamServer's private-listener server certificate).
existingSecret: ""
issuerRef: {}
# group: cert-manager.io
# kind: ClusterIssuer
# name: internal-ca
# --- Standalone IAM API Server ---
# Deploys a separate `versitygw iam` server as its own Deployment and public/
# private Services --
# an AWS-compatible IAM Query API, independently scalable and centralized
# (unlike iam.type: internal, which runs file-backed IAM inside each gateway
# pod). Manage users/roles/policies against its public control-plane API
# (reusing the gateway root Secret by default, or `iamServer.auth`); point
# gateways at it via iam.type: standalone.
iamServer:
enabled: false
replicaCount: 1
# Deployment strategy override for Vault storage. Internal file storage
# always uses Recreate to prevent concurrent writers and ReadWriteOnce
# multi-attach failures. Empty uses Kubernetes' default RollingUpdate for Vault.
strategy: {}
auth:
# Optional Secret containing rootAccessKeyId and rootSecretAccessKey.
# Empty reuses the top-level auth Secret for backward compatibility.
existingSecret: ""
# Optional image override; defaults to the top-level `image` values when unset.
image:
repository: ""
tag: ""
pullPolicy: ""
# Public control-plane API port (aws iam create-user, list-roles, etc.).
port: 7070
maxConnections: 250000
maxRequests: 100000
# Silence stdout request logging.
quiet: false
# Debug logger verbosity: "silent" (default), "debug", or "unsafe" -- see
# gateway.logLevel for details.
logLevel: silent
# Reject CreateOpenIDConnectProvider requests that omit ThumbprintList
# instead of auto-fetching it over an outbound TLS connection to the
# caller-supplied URL. Recommended for restricted/air-gapped clusters.
disableOidcThumbprintAutofetch: false
# Optional TLS for the public control-plane API. No cert-manager automation
# here -- bring your own Secret (must contain tls.crt / tls.key).
tls:
enabled: false
secretName: ""
# -- Storage backend --
storage:
# internal (file-backed, requires persistence below) | vault
type: internal
vault:
endpointUrl: ""
namespace: ""
secretStoragePath: ""
secretStorageNamespace: ""
authMethod: ""
authNamespace: ""
mountPath: ""
roleId: ""
# Secret containing sensitive Vault auth material. Recognized keys
# (provide whichever your vault-auth-method needs):
# roleSecret -- AppRole secret ID (VGW_IAM_VAULT_ROLE_SECRET)
# rootToken -- Vault root token (VGW_IAM_VAULT_ROOT_TOKEN)
existingSecret: ""
# Separate Secret for Vault's TLS material -- kept distinct from
# `existingSecret` above (auth credentials) since these are a different
# security concern (transport trust vs. identity). Recognized keys
# (provide whichever your vault-endpoint-url/mTLS setup needs):
# serverCert -- CA cert verifying Vault's server certificate (VGW_IAM_VAULT_SERVER_CERT)
# clientCert -- client cert for mTLS to Vault (VGW_IAM_VAULT_CLIENT_CERT)
# clientCertKey -- private key for clientCert (VGW_IAM_VAULT_CLIENT_CERT_KEY)
# Ignored for any of the three that has a literal value below.
tlsExistingSecret: ""
# PEM-encoded certificate content (literal text, not a file path).
# Prefer tlsExistingSecret above for production; these are stored in
# Helm release history in plaintext.
serverCert: ""
clientCert: ""
clientCertKey: ""
# -- Private mTLS endpoint --
# Serves the derive-signing-key/evaluate-policy/resolve-identity calls that
# gateways configured with iam.type: standalone use internally. Required
# for any such gateway to reach this service over TCP.
private:
enabled: true
port: 7443
certificate:
# Auto-provision the server certificate for this listener via
# cert-manager. issuerRef must be a CA-type issuer -- see
# iam.standalone.certificate for the matching client-side requirement.
create: false
# Use an existing Secret instead (or as well as -- existingSecret wins
# when both are set). Must contain tls.crt, tls.key, and ca.crt (the CA
# that signs gateway client certificates).
existingSecret: ""
issuerRef: {}
# group: cert-manager.io
# kind: ClusterIssuer
# name: internal-ca
# DNS names for the certificate. Defaults to the in-chart Service's
# names when left empty.
dnsNames: []
service:
# Type of the public control-plane Service. The private Service is always
# ClusterIP and is not exposed when this is NodePort or LoadBalancer.
type: ClusterIP
# Storage for the standalone IAM service's own file-backed data (storage.type: internal).
persistence:
enabled: true
create: true
claimName: ""
size: 1Gi
storageClassName: ""
accessMode: ReadWriteOnce
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
deploymentAnnotations: {}
podAnnotations: {}
podLabels: {}
# Extra environment variables to pass to the container.
# Use this to configure advanced options not covered above (e.g. event notifications,
# LDAP IAM, S3 proxy backend credentials, StatsD metrics, etc.).
@@ -389,9 +574,11 @@ topologySpreadConstraints: []
networkPolicy:
enabled: false
# allowIngressFromNamespaces:
# matchLabels:
# kubernetes.io/metadata.name: kube-system
# allowIngressFromPods:
# matchLabels:
# svccontroller.k3s.cattle.io/svcname: versitygw
# Label maps used as matchLabels selectors. When both are set, a source pod
# must match both selectors. A pod-only selector applies to this release's
# namespace; an empty pair denies ingress to the gateway. The IAM policy
# always permits this release's gateway pods to reach its private mTLS port.
allowIngressFromNamespaces: {}
# kubernetes.io/metadata.name: kube-system
allowIngressFromPods: {}
# svccontroller.k3s.cattle.io/svcname: versitygw
+2 -2
View File
@@ -17,14 +17,14 @@ backend="${VGW_BACKEND:-}"
if [ -z "$backend" ]; then
cat >&2 <<'EOF'
No command arguments were provided and VGW_BACKEND is unset.
Set VGW_BACKEND to one of: posix, scoutfs, s3, azure, plugin
Set VGW_BACKEND to one of: posix, scoutfs, s3, azure, plugin, iam
or pass explicit arguments to the container to run the versitygw command directly.
EOF
exit 1
fi
case "$backend" in
posix|scoutfs|s3|azure|plugin)
posix|scoutfs|s3|azure|plugin|iam)
;;
*)
echo "VGW_BACKEND invalid backend (was '$backend')." >&2