mirror of
https://github.com/versity/versitygw.git
synced 2026-08-28 03:46:17 +00:00
Merge pull request #2296 from versity/sis/iam-helm
feat: add Helm chart support for the standalone IAM service
This commit is contained in:
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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 }}
|
||||
@@ -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 }}
|
||||
@@ -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 }}
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user