diff --git a/charts/plane-enterprise/Chart.yaml b/charts/plane-enterprise/Chart.yaml index df097b2..2b5e506 100644 --- a/charts/plane-enterprise/Chart.yaml +++ b/charts/plane-enterprise/Chart.yaml @@ -5,7 +5,7 @@ description: Meet Plane. An Enterprise software development tool to manage issue type: application -version: 2.6.1 +version: 2.7.0 appVersion: "2.6.3" home: https://plane.so/ diff --git a/charts/plane-enterprise/README.md b/charts/plane-enterprise/README.md index 1906ea5..aa27504 100644 --- a/charts/plane-enterprise/README.md +++ b/charts/plane-enterprise/README.md @@ -189,26 +189,51 @@ The default value is `"traefik"`. If you are switching to a standard ingress con | Setting | Default | Required | Description | | ----------------------- | :-----: | :------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | airgapped.enabled | false | No | Specifies the airgapped mode the Plane API runs in. | -| airgapped.s3Secrets | [] | No | List of Kubernetes Secrets containing CA certificates to install. Each item must have `name` (Secret name) and `key` (file key in the Secret). Example: `kubectl -n plane create secret generic plane-s3-ca --from-file=s3-custom-ca.crt=/path/to/ca.crt`. Supports multiple certs (e.g. S3 + internal CA). | -| airgapped.s3SecretName | "" | No | **(Deprecated, backward compatibility)** Name of a single Kubernetes Secret containing the S3 CA cert. Used only when `s3Secrets` is empty. Prefer migrating to `s3Secrets`. | -| airgapped.s3SecretKey | "" | No | **(Deprecated, backward compatibility)** Key (filename) of the cert file inside the Secret. Used only when `s3Secrets` is empty. Set together with `airgapped.s3SecretName`. | +| airgapped.s3Secrets | [] | No | **(Deprecated, backward compatibility)** Custom S3 CA configuration moved to the top-level `customCA` section and no longer requires airgapped mode. Still honored as a fallback when `customCA.*` is unset. Prefer `customCA.s3Secrets`. | +| airgapped.s3SecretName | "" | No | **(Deprecated, backward compatibility)** Single-secret fallback. Used only when no `customCA.*` and no `airgapped.s3Secrets` are set. Prefer `customCA.s3Secrets`. | +| airgapped.s3SecretKey | "" | No | **(Deprecated, backward compatibility)** Key (filename) of the cert file for the deprecated single-secret fallback. Set together with `airgapped.s3SecretName`. | -#### Backward compatibility: custom S3 CA (upgrading from older charts) +### Custom CA Certificates -If you previously used the single-secret custom CA configuration (`airgapped.s3SecretName` and `airgapped.s3SecretKey`), it continues to work. No change is required when upgrading. +Use this when your object storage / S3-compatible endpoint presents a certificate signed by a private or internal CA. It is **independent of `airgapped.enabled`** — set it in any deployment (including non-airgapped). The chart mounts the cert(s) into the relevant pods, runs `update-ca-certificates`, and points the runtime (including Node.js via `NODE_EXTRA_CA_CERTS` and boto via `AWS_CA_BUNDLE`) at the resulting bundle. -- **Old configuration (still supported):** Set `airgapped.s3SecretName` to your Secret name and `airgapped.s3SecretKey` to the key (e.g. `s3-custom-ca.crt`). The chart mounts that single cert, runs `update-ca-certificates`, and sets `AWS_CA_BUNDLE` to the system bundle path. -- **New configuration (recommended):** Use `airgapped.s3Secrets` with a list of `{ name, key }` entries. This allows multiple CA certificates (e.g. S3 endpoint CA and internal PKI) and matches the same runtime behavior. +| Setting | Default | Required | Description | +| --------------------- | :-----: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| customCA.s3Secrets | [] | No | List of Kubernetes Secrets containing CA certificates to install. Each item must have `name` (Secret name) and `key` (file key in the Secret). Example: `kubectl -n plane create secret generic plane-s3-ca --from-file=s3-custom-ca.crt=/path/to/ca.crt`. Supports multiple certs (e.g. S3 + internal CA). | +| customCA.s3SecretName | "" | No | Single-secret form. Name of a Kubernetes Secret containing the CA cert. Used only when `customCA.s3Secrets` is empty. Prefer `customCA.s3Secrets`. | +| customCA.s3SecretKey | "" | No | Key (filename) of the cert file inside the Secret. Used only when `customCA.s3Secrets` is empty. Set together with `customCA.s3SecretName`. | -**Migration (optional):** To move from the deprecated keys to `s3Secrets`, set for example: +Resolution precedence is: `customCA.s3Secrets` → `customCA.s3SecretName`/`s3SecretKey` → `airgapped.s3Secrets` → `airgapped.s3SecretName`/`s3SecretKey`. + +Example: ```yaml +customCA: + s3Secrets: + - name: plane-s3-ca + key: s3-custom-ca.crt + - name: plane-internal-ca + key: internal-ca.crt +``` + +#### Backward compatibility (upgrading from older charts) + +If you previously configured custom CA certs under `airgapped.*` (`airgapped.s3Secrets`, or `airgapped.s3SecretName`/`s3SecretKey`), they continue to work as a fallback — **no change is required when upgrading**. To migrate, move the same values to the `customCA` section: + +```yaml +# Before airgapped: enabled: true s3Secrets: - - name: plane-s3-ca # same as your previous s3SecretName - key: s3-custom-ca.crt # same as your previous s3SecretKey - # s3SecretName and s3SecretKey can be removed after migration + - name: plane-s3-ca + key: s3-custom-ca.crt + +# After +customCA: + s3Secrets: + - name: plane-s3-ca + key: s3-custom-ca.crt +# airgapped.s3* can be removed; airgapped.enabled is no longer required for custom CA ``` ### Pod Security (PSA `restricted`) diff --git a/charts/plane-enterprise/templates/_helpers.tpl b/charts/plane-enterprise/templates/_helpers.tpl index 8566725..e5b7b57 100644 --- a/charts/plane-enterprise/templates/_helpers.tpl +++ b/charts/plane-enterprise/templates/_helpers.tpl @@ -65,15 +65,43 @@ of the local_setup flag's value. {{- end -}} {{/* -Normalize the deprecated s3SecretName/s3SecretKey into the s3Secrets list format. -Returns "true" when airgapped is enabled and at least one CA secret is configured. +Returns "true" when at least one custom CA secret is configured, in either the +top-level `customCA` section or the legacy `airgapped` keys. This is decoupled +from `airgapped.enabled` so custom CA certs can be mounted in non-airgapped +deployments (e.g. an S3-compatible endpoint that uses a private CA). */}} {{- define "plane.s3CAEnabled" -}} - {{- if and .Values.airgapped.enabled (or (gt (len .Values.airgapped.s3Secrets) 0) (and .Values.airgapped.s3SecretName .Values.airgapped.s3SecretKey)) -}} + {{- if or (gt (len .Values.customCA.s3Secrets) 0) (and .Values.customCA.s3SecretName .Values.customCA.s3SecretKey) (gt (len .Values.airgapped.s3Secrets) 0) (and .Values.airgapped.s3SecretName .Values.airgapped.s3SecretKey) -}} true {{- end -}} {{- end -}} +{{/* +Resolve the effective list of CA secrets and render them as projected-volume sources. +Precedence: customCA.s3Secrets > customCA single secret > airgapped.s3Secrets > airgapped single secret. +Single-secret (legacy) configs are normalized into the same { name, key } shape. +Output starts at column 0; caller controls indentation (e.g. nindent). +*/}} +{{- define "plane.s3CAProjectedSources" -}} +{{- $secrets := list -}} +{{- if gt (len .Values.customCA.s3Secrets) 0 -}} + {{- $secrets = .Values.customCA.s3Secrets -}} +{{- else if and .Values.customCA.s3SecretName .Values.customCA.s3SecretKey -}} + {{- $secrets = list (dict "name" .Values.customCA.s3SecretName "key" .Values.customCA.s3SecretKey) -}} +{{- else if gt (len .Values.airgapped.s3Secrets) 0 -}} + {{- $secrets = .Values.airgapped.s3Secrets -}} +{{- else if and .Values.airgapped.s3SecretName .Values.airgapped.s3SecretKey -}} + {{- $secrets = list (dict "name" .Values.airgapped.s3SecretName "key" .Values.airgapped.s3SecretKey) -}} +{{- end -}} +{{- range $secrets }} +- secret: + name: {{ .name }} + items: + - key: {{ .key }} + path: {{ .key }} +{{- end }} +{{- end -}} + {{/* Render the volumes block for custom S3 CA certificates. Always uses a projected volume so both single-secret (legacy) and multi-secret configs @@ -86,21 +114,7 @@ volumes: - name: s3-custom-ca projected: sources: - {{- if gt (len .Values.airgapped.s3Secrets) 0 }} - {{- range .Values.airgapped.s3Secrets }} - - secret: - name: {{ .name }} - items: - - key: {{ .key }} - path: {{ .key }} - {{- end }} - {{- else }} - - secret: - name: {{ .Values.airgapped.s3SecretName }} - items: - - key: {{ .Values.airgapped.s3SecretKey }} - path: {{ .Values.airgapped.s3SecretKey }} - {{- end }} + {{- include "plane.s3CAProjectedSources" . | trim | nindent 8 }} {{- end }} {{- end -}} @@ -164,21 +178,7 @@ volumes: - name: s3-custom-ca projected: sources: - {{- if gt (len .Values.airgapped.s3Secrets) 0 }} - {{- range .Values.airgapped.s3Secrets }} - - secret: - name: {{ .name }} - items: - - key: {{ .key }} - path: {{ .key }} - {{- end }} - {{- else }} - - secret: - name: {{ .Values.airgapped.s3SecretName }} - items: - - key: {{ .Values.airgapped.s3SecretKey }} - path: {{ .Values.airgapped.s3SecretKey }} - {{- end }} + {{- include "plane.s3CAProjectedSources" . | trim | nindent 8 }} - name: ca-bundle emptyDir: {} {{- end }} diff --git a/charts/plane-enterprise/values.yaml b/charts/plane-enterprise/values.yaml index 6913c4b..8245c10 100644 --- a/charts/plane-enterprise/values.yaml +++ b/charts/plane-enterprise/values.yaml @@ -14,9 +14,20 @@ license: airgapped: enabled: false - # The boto module used by API does not use the CA bundles in the container, so we need to - # mount the CA bundle into the API pod by passing it in as an environment - # variable. + # DEPRECATED: custom S3 CA configuration has moved to the top-level `customCA` + # section and no longer requires airgapped mode. These keys are still honored + # as a fallback for backward compatibility - prefer `customCA.*` going forward. + s3Secrets: [] + s3SecretName: "" + s3SecretKey: "" + +# Custom CA certificates for object storage / S3-compatible endpoints whose +# certificates are signed by a private or internal CA. This is independent of +# `airgapped.enabled` - set it whenever your storage endpoint presents a custom +# CA, including non-airgapped deployments. +# The boto module used by the API does not use the OS CA bundle, so the chart +# mounts these certs into the relevant pods and points the runtime at them. +customCA: # Preferred: list of Kubernetes Secrets containing CA certificates (supports multiple certs). # Example: # s3Secrets: @@ -26,8 +37,8 @@ airgapped: # key: s3-custom-ca-2.crt s3Secrets: [] - # Deprecated (backward compatibility): use a single secret for custom S3 CA. - # If set, used when s3Secrets is empty. Prefer migrating to s3Secrets. + # Single-secret form (backward compatible). Used only when s3Secrets is empty. + # Prefer migrating to s3Secrets. # Example: # s3SecretName: plane-s3-ca # s3SecretKey: s3-custom-ca.crt