Merge branch 'main' into release

This commit is contained in:
Kevin Fox
2026-08-23 06:28:23 -07:00
96 changed files with 3467 additions and 916 deletions
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
# Verify that the shields.io version badges in each top-level chart README
# agree with the version and appVersion declared in the sibling Chart.yaml.
# Nothing regenerates those badges, so they drift silently as charts are bumped.
#
# READMEs without a Version badge (library charts, hand written docs) are
# skipped. A leading 'v' is ignored when comparing, so 'v0.3.0' matches '0.3.0'.
set -euo pipefail
SCRIPT="$(readlink -f "$0")"
SCRIPTPATH="$(dirname "${SCRIPT}")"
REPO_ROOT="$(dirname "${SCRIPTPATH}")/.."
function print_problem {
echo >&2 " ❌ ${*}"
}
function require_command {
command -v "$1" >/dev/null 2>&1 || {
print_problem "$2"
exit 1
}
}
# Print the value of a shields.io badge as "<alt text> <url value>", or nothing
# at all when the badge is absent. Each version is spelled twice in the badge
# markup, and both spellings need checking.
function badge_values {
local readme="$1"
local name="$2"
local badge alt url
badge="$(grep -o "!\[${name}: [^]]*\](https://img.shields.io/badge/${name}-[^)]*)" "${readme}" | head -1 || true)"
if [ -z "${badge}" ]; then
return 0
fi
alt="$(printf '%s' "${badge}" | sed "s#^!\[${name}: \([^]]*\)\].*#\1#")"
# shields.io escapes a literal dash in the value as '--'
url="$(printf '%s' "${badge}" | sed "s#.*/badge/${name}-\(.*\)-informational.*#\1#; s#--#-#g")"
printf '%s %s' "${alt}" "${url}"
}
# Compare two versions, ignoring a single leading 'v' on either side.
function versions_match {
[ "${1#v}" = "${2#v}" ]
}
require_command yq 'yq is required to run this script'
problems=0
for chart_yaml in "${REPO_ROOT}"/charts/*/Chart.yaml; do
[ -f "${chart_yaml}" ] || continue
chart_dir="$(dirname "${chart_yaml}")"
readme="${chart_dir}/README.md"
label="charts/$(basename "${chart_dir}")/README.md"
[ -f "${readme}" ] || continue
version_badge="$(badge_values "${readme}" Version)"
if [ -z "${version_badge}" ]; then
# No version badges in this README, nothing to keep in sync.
continue
fi
chart_version="$(yq e '.version // ""' "${chart_yaml}")"
chart_app_version="$(yq e '.appVersion // ""' "${chart_yaml}")"
version_alt="${version_badge%% *}"
version_url="${version_badge##* }"
if ! versions_match "${version_alt}" "${chart_version}"; then
print_problem "${label}: Version badge ${version_alt} does not match Chart.yaml version ${chart_version}"
problems=$((problems + 1))
fi
if [ "${version_url}" != "${version_alt}" ]; then
print_problem "${label}: Version badge text (${version_alt}) and image URL (${version_url}) disagree"
problems=$((problems + 1))
fi
app_badge="$(badge_values "${readme}" AppVersion)"
if [ -z "${app_badge}" ]; then
if [ -n "${chart_app_version}" ]; then
print_problem "${label}: has a Version badge but no AppVersion badge, while Chart.yaml declares appVersion ${chart_app_version}"
problems=$((problems + 1))
fi
continue
fi
app_alt="${app_badge%% *}"
app_url="${app_badge##* }"
if [ -z "${chart_app_version}" ]; then
print_problem "${label}: AppVersion badge is ${app_alt} but Chart.yaml declares no appVersion"
problems=$((problems + 1))
elif ! versions_match "${app_alt}" "${chart_app_version}"; then
print_problem "${label}: AppVersion badge ${app_alt} does not match Chart.yaml appVersion ${chart_app_version}"
problems=$((problems + 1))
fi
if [ "${app_url}" != "${app_alt}" ]; then
print_problem "${label}: AppVersion badge text (${app_alt}) and image URL (${app_url}) disagree"
problems=$((problems + 1))
fi
done
if [ "${problems}" -ne 0 ]; then
print_problem "${problems} README version badge problem(s) found. Update the badges to match Chart.yaml."
exit 1
fi
+8
View File
@@ -25,6 +25,14 @@ $(kubectl get pods -o name -n "$1" | while read -r line; do echo logs for "${lin
$( ([[ -n "$2" ]] && kubectl get pods -o name -n "$2") | while read -r line; do echo logs for "${line}"; kubectl logs -n "$2" "${line}" --all-containers=true --ignore-errors=true; done) $( ([[ -n "$2" ]] && kubectl get pods -o name -n "$2") | while read -r line; do echo logs for "${line}"; kubectl logs -n "$2" "${line}" --all-containers=true --ignore-errors=true; done)
\`\`\` \`\`\`
MAX_BYTES=1048576
if [ "$(wc -c < "${GITHUB_STEP_SUMMARY}")" -gt "${MAX_BYTES}" ]; then
# shellcheck disable=SC2094
truncate -s $((MAX_BYTES - 14)) "${GITHUB_STEP_SUMMARY}"
# shellcheck disable=SC2094
printf "\ntruncated...\n" >> "${GITHUB_STEP_SUMMARY}"
fi
EOF EOF
} }
@@ -10,6 +10,7 @@ on:
- '.github/tests/**/*.yaml' - '.github/tests/**/*.yaml'
- '.github/tests/**/*.sh' - '.github/tests/**/*.sh'
- '.github/tests/**/*.json' - '.github/tests/**/*.json'
- '.github/scripts/check-readme-versions.sh'
- 'examples/**/*.yaml' - 'examples/**/*.yaml'
- 'helm-docs.sh' - 'helm-docs.sh'
+17
View File
@@ -16,6 +16,7 @@ on:
- '.github/tests/**/*.yaml' - '.github/tests/**/*.yaml'
- '.github/tests/**/*.sh' - '.github/tests/**/*.sh'
- '.github/tests/**/*.json' - '.github/tests/**/*.json'
- '.github/scripts/check-readme-versions.sh'
- 'examples/**/*.yaml' - 'examples/**/*.yaml'
- 'examples/**/*.sh' - 'examples/**/*.sh'
- 'tests/**/*' - 'tests/**/*'
@@ -42,6 +43,22 @@ jobs:
- name: Verify Docs updated - name: Verify Docs updated
run: ./helm-docs.sh run: ./helm-docs.sh
- name: Verify README version badges
run: |
set +e
.github/scripts/check-readme-versions.sh 2>/tmp/badge-findings
res=$?
if [ $res -ne 0 ]; then
{
echo "## README version badges"
echo
echo ":x: These chart READMEs have version badges that disagree with their Chart.yaml. Please fix."
echo
cat /tmp/badge-findings
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: Verify Spire appVersion - name: Verify Spire appVersion
run: | run: |
set +e set +e
@@ -29,7 +29,7 @@ jobs:
with: with:
cosign-release: v2.2.3 cosign-release: v2.2.3
- name: Install regctl - name: Install regctl
uses: regclient/actions/regctl-installer@5c882eb04fcca27ebb4f5904e0da01f0780063ea # main uses: regclient/actions/regctl-installer@78eb729dbdb4ef6480e85ff697b4410e22112583 # main
- name: Log in to GHCR - name: Log in to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with: with:
+5
View File
@@ -15,6 +15,11 @@ lint-release: ## Lint the charts using chart-testing for release
@echo Linting charts… @echo Linting charts…
@ct lint --config ct.yaml --target-branch $(TARGET_BRANCH) @ct lint --config ct.yaml --target-branch $(TARGET_BRANCH)
.PHONY: check-readme-versions
check-readme-versions: ## Verify chart README version badges match Chart.yaml
@echo Checking README version badges…
@.github/scripts/check-readme-versions.sh
##@ Testing: (ensure to run on dedicated test cluster) ##@ Testing: (ensure to run on dedicated test cluster)
.PHONY: clean-test-leftovers .PHONY: clean-test-leftovers
+3 -3
View File
@@ -1,9 +1,9 @@
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: step-certificates - name: step-certificates
repository: https://smallstep.github.io/helm-charts/ repository: https://smallstep.github.io/helm-charts/
version: 1.27.4 version: 1.27.4
digest: sha256:b41dcd4ef1a70026a96cbd6b704ae22b7c62c139d3cf699ac746366658698825 digest: sha256:11d3748666d0c9aa04a77a01ed3cde99553aae715bc9f00b311247e6a9c6ee91
generated: "2026-07-31T16:55:06.703514-07:00" generated: "2026-08-21T14:41:49.31784-07:00"
+2 -2
View File
@@ -13,7 +13,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.3.0 version: 0.3.1
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
@@ -30,7 +30,7 @@ maintainers:
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: step-certificates - name: step-certificates
alias: step alias: step
repository: https://smallstep.github.io/helm-charts/ repository: https://smallstep.github.io/helm-charts/
+1 -1
View File
@@ -4,7 +4,7 @@ description: >
A Helm chart for deploying the Spire CRDS A Helm chart for deploying the Spire CRDS
type: application type: application
version: 0.6.0 version: 0.6.1
appVersion: "0.0.1" appVersion: "0.0.1"
keywords: ["spire-crds"] keywords: ["spire-crds"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
+1 -1
View File
@@ -1,6 +1,6 @@
# spire-crds # spire-crds
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.7.2](https://img.shields.io/badge/AppVersion-1.7.2-informational?style=flat-square) ![Version: 0.6.1](https://img.shields.io/badge/Version-0.6.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.0.1](https://img.shields.io/badge/AppVersion-0.0.1-informational?style=flat-square)
A Helm chart to install the SPIRE CRDS. A Helm chart to install the SPIRE CRDS.
+3 -3
View File
@@ -1,6 +1,6 @@
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
digest: sha256:b09e1da391c6df954369ee679f0757522fb39afe9a8e6bdc77c25d048fb30340 digest: sha256:fd4f15738349c83d9a1c60a1529ecc5cb8df6ecd9af21176df54f61f40d8973e
generated: "2026-07-31T16:55:07.148848-07:00" generated: "2026-08-21T14:41:50.554693-07:00"
+3 -3
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: spire-ha-agent name: spire-ha-agent
description: A Helm chart to install the SPIRE HA agent. description: A Helm chart to install the SPIRE HA agent.
type: application type: application
version: 0.3.0 version: 0.3.1
appVersion: "0.2.0" appVersion: "0.3.0"
keywords: ["spiffe", "spire-ha-agent"] keywords: ["spiffe", "spire-ha-agent"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-ha-agent home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-ha-agent
sources: sources:
@@ -20,4 +20,4 @@ maintainers:
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
+1 -1
View File
@@ -1,6 +1,6 @@
# spire-ha-agent # spire-ha-agent
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.7.2](https://img.shields.io/badge/AppVersion-1.7.2-informational?style=flat-square) ![Version: 0.3.1](https://img.shields.io/badge/Version-0.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.3.0](https://img.shields.io/badge/AppVersion-0.3.0-informational?style=flat-square)
A Helm chart to install the SPIRE HA agent. A Helm chart to install the SPIRE HA agent.
+3 -3
View File
@@ -1,6 +1,6 @@
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
digest: sha256:b09e1da391c6df954369ee679f0757522fb39afe9a8e6bdc77c25d048fb30340 digest: sha256:fd4f15738349c83d9a1c60a1529ecc5cb8df6ecd9af21176df54f61f40d8973e
generated: "2026-07-31T16:55:07.22031-07:00" generated: "2026-08-21T14:41:50.632935-07:00"
+3 -3
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: spire-identity-exchange name: spire-identity-exchange
description: A Helm chart to install the SPIRE Identity Exchange. description: A Helm chart to install the SPIRE Identity Exchange.
type: application type: application
version: 0.2.0 version: 0.2.1
appVersion: "v0.3.0" appVersion: "v0.5.0"
keywords: ["spiffe", "spire", "identity exchange"] keywords: ["spiffe", "spire", "identity exchange"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-identity-exchange home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-identity-exchange
sources: sources:
@@ -20,4 +20,4 @@ maintainers:
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
+221 -117
View File
@@ -1,6 +1,6 @@
# spire-identity-exchange # spire-identity-exchange
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.3.0](https://img.shields.io/badge/AppVersion-0.3.0-informational?style=flat-square) ![Version: 0.2.1](https://img.shields.io/badge/Version-0.2.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.5.0](https://img.shields.io/badge/AppVersion-v0.5.0-informational?style=flat-square)
A Helm chart to install the SPIRE Identity Exchange. A Helm chart to install the SPIRE Identity Exchange.
@@ -18,125 +18,229 @@ A Helm chart to install the SPIRE Identity Exchange.
* <https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-identity-exchange> * <https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-identity-exchange>
## Listeners
Serving is a two-axis matrix: protocol (gRPC or REST) crossed with the source of the
certificate the listener presents. All four listeners are independent and can run at once.
| Values block | Serves with | Default port | Default |
| -------------- | ---------------------------------------------------------- | ------------ | ------- |
| `tls.rest` | the certificate from `tls.externalSecret` / `tls.certManager` | 8444 | off |
| `tls.grpc` | the certificate from `tls.externalSecret` / `tls.certManager` | 8443 | off |
| `spiffe.rest` | this deployment's own X509-SVID | 8544 | **on** |
| `spiffe.grpc` | this deployment's own X509-SVID | 8543 | off |
The `spiffe.*` listeners need no certificate files: the SVID is fetched from the SPIRE Agent
Workload API and rotated automatically, so a SPIFFE-only install requires neither cert-manager
nor a TLS Secret. A cert source under `tls:` is required only when `tls.rest` or `tls.grpc` is
enabled. Client authentication is identical on all four — callers present a bearer token.
With `tls.certManager`, the requested certificate's `dnsNames` are taken from whichever exposures
are enabled — the `ingress.host`, the `gatewayAPI.host`, or both — across every enabled `tls.*`
listener, deduplicated. Each enabled `tls.*` listener must therefore have an ingress or a gateway
enabled, unless you set `tls.certManager.certificate.dnsNames` explicitly.
## The stack selector
Every exchange addresses a **stack**: an entry in `auth.stacks`, or — with
`auth.passthroughPlugins` (the default) — a single plugin addressed under its own name. It is
the `{stack}` segment of the REST path (`/api/v1/svid/{stack}/x509`).
As of app version v0.4.0 the exchange asserts one selector on its own behalf, naming the stack
that was addressed:
| Selector type | Value | Example |
| ------------------------ | ---------------------- | ---------------------------------------------- |
| `spire_identity_exchange` | `stack:name:<stack>` | `spire_identity_exchange:stack:name:k8s_psat` |
Add it to a registration entry to scope that entry to a single stack:
```yaml
controllerManager:
identities:
clusterStaticEntries:
test:
selectors:
- k8s_psat:namespace:default
- k8s_psat:service_account_name:default
- spire_identity_exchange:stack:name:k8s_psat # only issuable via this stack
```
<!-- The parameters section is generated using helm-docs.sh and should not be edited by hand. --> <!-- The parameters section is generated using helm-docs.sh and should not be edited by hand. -->
## Parameters ## Parameters
### Chart parameters ### Chart parameters
| Name | Description | Value | | Name | Description | Value |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `agentSocketName` | The name of the spire-agent unix socket | `spire-agent.sock` | | `agentSocketName` | The name of the spire-agent unix socket | `spire-agent.sock` |
| `csiDriverName` | The csi driver to use | `csi.spiffe.io` | | `csiDriverName` | The csi driver to use | `csi.spiffe.io` |
| `replicaCount` | Replica count | `1` | | `replicaCount` | Replica count | `1` |
| `namespaceOverride` | Namespace override | `""` | | `namespaceOverride` | Namespace override | `""` |
| `annotations` | Annotations for the deployment | `{}` | | `annotations` | Annotations for the deployment | `{}` |
| `labels` | Labels for the deployment | `{}` | | `labels` | Labels for the deployment | `{}` |
| `image.registry` | The OCI registry to pull the image from | `ghcr.io` | | `image.registry` | The OCI registry to pull the image from | `ghcr.io` |
| `image.repository` | The repository within the registry | `spiffe/spire-identity-exchange-server` | | `image.repository` | The repository within the registry | `spiffe/spire-identity-exchange-server` |
| `image.pullPolicy` | The image pull policy | `IfNotPresent` | | `image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` |
| `spireServerAttestorSPIFFEWorkloadAPI.resources` | Resource requests and limits | `{}` | | `spireAgent.resources` | Resource requests and limits | `{}` |
| `spireServerAttestorSPIFFEWorkloadAPI.image.registry` | The OCI registry to pull the image from | `ghcr.io` | | `spireAgent.image.registry` | The OCI registry to pull the image from | `ghcr.io` |
| `spireServerAttestorSPIFFEWorkloadAPI.image.repository` | The repository within the registry | `spiffe/spire-server-attestor-spiffe-workload-api` | | `spireAgent.image.repository` | The repository within the registry | `spiffe/spire-agent` |
| `spireServerAttestorSPIFFEWorkloadAPI.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `spireAgent.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `spireServerAttestorSPIFFEWorkloadAPI.image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `spireAgent.image.tag` | Overrides the image tag whose default is the chart appVersion | `1.15.3` |
| `spireAgent.resources` | Resource requests and limits | `{}` | | `extraEnv` | Extra environment variables to add to the spire identity exchange | `[]` |
| `spireAgent.image.registry` | The OCI registry to pull the image from | `ghcr.io` | | `resources` | Resource requests and limits | `{}` |
| `spireAgent.image.repository` | The repository within the registry | `spiffe/spire-agent` | | `configMap.annotations` | Annotations to add to the SPIRE Identity Exchange ConfigMap | `{}` |
| `spireAgent.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `podSecurityContext` | Pod security context for SPIRE Identity Exchange pods | `{}` |
| `spireAgent.image.tag` | Overrides the image tag whose default is the chart appVersion | `1.15.2` | | `securityContext` | Security context for SPIRE Identity Exchange deployment | `{}` |
| `extraEnv` | Extra environment variables to add to the spire identity exchange | `[]` | | `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` |
| `resources` | Resource requests and limits | `{}` | | `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` |
| `configMap.annotations` | Annotations to add to the SPIRE Identity Exchange ConfigMap | `{}` | | `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` |
| `podSecurityContext` | Pod security context for SPIRE Identity Exchange pods | `{}` | | `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `5` |
| `securityContext` | Security context for SPIRE Identity Exchange deployment | `{}` | | `podAnnotations` | Pod annotations for SPIRE Identity Exchange | `{}` |
| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | | `podLabels` | Labels to add to pods | `{}` |
| `readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | | `config.logLevel` | The log level, valid values are "debug", "info", "warn", and "error" | `info` |
| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | | `config.logFormat` | The log format, valid values are "text" and "json" | `text` |
| `livenessProbe.periodSeconds` | Period seconds for livenessProbe | `5` | | `telemetry.prometheus.port` | Port for prometheus metrics | `4950` |
| `podAnnotations` | Pod annotations for SPIRE Identity Exchange | `{}` | | `telemetry.prometheus.podMonitor.enabled` | Enable podMonitor for prometheus | `false` |
| `podLabels` | Labels to add to pods | `{}` | | `telemetry.prometheus.podMonitor.namespace` | Override where to install the podMonitor, if not set will use the same namespace as the helm release | `""` |
| `tls.externalSecret.enabled` | Provide your own certificate/key via tls style Kubernetes Secret | `false` | | `telemetry.prometheus.podMonitor.labels` | Pod labels to filter for prometheus monitoring | `{}` |
| `tls.externalSecret.secretName` | Specify which Secret to use | `""` | | `imagePullSecrets` | Image pull secret names | `[]` |
| `tls.certManager.enabled` | Use certificateManager to create the certificate | `false` | | `nameOverride` | Name override | `""` |
| `tls.certManager.issuer.create` | Create an issuer to use to issue the certificate | `true` | | `fullnameOverride` | Full name override | `""` |
| `tls.certManager.issuer.acme.email` | Must be set in order to register with LetsEncrypt. By setting, you agree to their Terms of Service | `""` | | `serviceAccount.create` | Specifies whether a service account should be created | `true` |
| `tls.certManager.issuer.acme.server` | Server to use to get certificate. Defaults to LetsEncrypt | `https://acme-v02.api.letsencrypt.org/directory` | | `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
| `tls.certManager.issuer.acme.solvers` | Configure the issuer solvers. Defaults to http01 via ingress. | `{}` | | `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated. | `""` |
| `tls.certManager.certificate.dnsNames` | Override the dnsNames on the certificate request. Defaults to the same settings as Ingress | `[]` | | `deleteHook.enabled` | Enable Helm hooks to autofix common delete issues (should be disabled when using `helm template`) | `true` |
| `tls.certManager.certificate.issuerRef.group` | If you are using an external plugin, specify the group for it here | `""` | | `autoscaling.enabled` | Flag to enable autoscaling | `false` |
| `tls.certManager.certificate.issuerRef.kind` | Kind of the issuer reference. Override if you want to use a ClusterIssuer | `Issuer` | | `autoscaling.minReplicas` | Minimum replicas for autoscaling | `1` |
| `tls.certManager.certificate.issuerRef.name` | Name of the issuer to use. If unset, it will use the name of the built in issuer | `""` | | `autoscaling.maxReplicas` | Maximum replicas for autoscaling | `5` |
| `config.logLevel` | The log level, valid values are "debug", "info", "warn", and "error" | `info` | | `autoscaling.targetCPUUtilizationPercentage` | Target CPU utlization that triggers autoscaling | `80` |
| `config.logFormat` | The log format, valid values are "text" and "json" | `text` | | `autoscaling.targetMemoryUtilizationPercentage` | Target Memory utlization that triggers autoscaling | `80` |
| `imagePullSecrets` | Image pull secret names | `[]` | | `nodeSelector` | Node selector | `{}` |
| `nameOverride` | Name override | `""` | | `tolerations` | list of tolerations | `[]` |
| `fullnameOverride` | Full name override | `""` | | `affinity` | Node affinity | `{}` |
| `serviceAccount.create` | Specifies whether a service account should be created | `true` | | `trustDomain` | Set the trust domain to be used for the SPIFFE identifiers | `example.org` |
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` | | `clusterName` | The name of this Kubernetes cluster, as it appears in SPIFFE ID paths | `example-cluster` |
| `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated. | `""` | | `jwtIssuer` | The issuer URL for JWT-SVIDs. Defaults to https://oidc-discovery.$trustDomain | `""` |
| `deleteHook.enabled` | Enable Helm hooks to autofix common delete issues (should be disabled when using `helm template`) | `true` | | `clusterDomain` | The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`) | `cluster.local` |
| `autoscaling.enabled` | Flag to enable autoscaling | `false` | | `auth.plugins.k8s_psat.enabled` | Enable the k8s psat plugin | `true` |
| `autoscaling.minReplicas` | Minimum replicas for autoscaling | `1` | | `auth.plugins.k8s_psat.config.audiences` | The audiences to allow | `[]` |
| `autoscaling.maxReplicas` | Maximum replicas for autoscaling | `5` | | `auth.plugins.k8s_psat.config.allowedServiceAccounts` | The service accounts that are allowed | `[]` |
| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utlization that triggers autoscaling | `80` | | `auth.plugins.spiffe.enabled` | Enable the spiffe plugin | `true` |
| `autoscaling.targetMemoryUtilizationPercentage` | Target Memory utlization that triggers autoscaling | `80` | | `auth.plugins.spiffe.keySource` | What source to use to fetch the keys. Can be oidc or oidcLocal. oidcLocal forces discoveryURL to be the internal discovery address. | `oidcLocal` |
| `nodeSelector` | Node selector | `{}` | | `auth.plugins.spiffe.csiDriverName` | The CSI driver providing the SPIRE Agent workload socket this plugin attests against. Defaults to the chart level csiDriverName. Requires config.connectWithTrustBundle. | |
| `tolerations` | iist of tolerations | `[]` | | `auth.plugins.spiffe.config.issuerURL` | The url to connect to for JWKS discovery | `${SPIFFE_JWT_ISSUER}` |
| `affinity` | Node affinity | `{}` | | `auth.plugins.spiffe.config.trustDomain` | The trust domain to use | `${SPIFFE_TRUST_DOMAIN}` |
| `trustDomain` | Set the trust domain to be used for the SPIFFE identifiers | `example.org` | | `auth.plugins.spiffe.config.pathPatterns` | The service accounts that are allowed | `[]` |
| `clusterDomain` | The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`) | `cluster.local` | | `auth.plugins.spiffe.config.audiences` | The audiences to allow | `[]` |
| `auth.plugins` | Plugins to load | `{}` | | `auth.plugins.spiffe.config.connectWithTrustBundle` | Use the trust bundle to validate the issuerURL | `true` |
| `auth.stacks` | Stacks to load | `{}` | | `auth.stacks.image_pull.enabled` | Enable the image_pull stack | `true` |
| `rest.enabled` | Enable the rest service | `true` | | `auth.stacks.image_pull.plugins` | List of plugins that are required by this stack | `[]` |
| `rest.service.type` | Service type | `ClusterIP` | | `auth.unsupportedBuiltInPlugins` | Unsupported mechanism to use plugins not yet supported by the chart. | `{}` |
| `rest.service.port` | port for the service | `443` | | `auth.passthroughPlugins` | Address each plugin as a stack of its own, in addition to any stacks defined | `false` |
| `rest.service.annotations` | Annotations for service resource | `{}` | | `tls.externalSecret.enabled` | Provide your own certificate/key via tls style Kubernetes Secret | `false` |
| `rest.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | | `tls.externalSecret.secretName` | Specify which Secret to use | `""` |
| `rest.ingress.enabled` | Flag to enable ingress | `false` | | `tls.certManager.enabled` | Use certificateManager to create the certificate | `false` |
| `rest.ingress.className` | Ingress class name | `""` | | `tls.certManager.issuer.create` | Create an issuer to use to issue the certificate | `true` |
| `rest.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` | | `tls.certManager.issuer.acme.email` | Must be set in order to register with LetsEncrypt. By setting, you agree to their Terms of Service | `""` |
| `rest.ingress.annotations` | Annotations for ingress object | `{}` | | `tls.certManager.issuer.acme.server` | Server to use to get certificate. Defaults to LetsEncrypt | `https://acme-v02.api.letsencrypt.org/directory` |
| `rest.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-rest` | | `tls.certManager.issuer.acme.solvers` | Configure the issuer solvers. Defaults to http01 via ingress. | `{}` |
| `rest.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` | | `tls.certManager.certificate.dnsNames` | Override the dnsNames on the certificate request. Defaults to the same settings as Ingress | `[]` |
| `rest.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` | | `tls.certManager.certificate.issuerRef.group` | If you are using an external plugin, specify the group for it here | `""` |
| `rest.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` | | `tls.certManager.certificate.issuerRef.kind` | Kind of the issuer reference. Override if you want to use a ClusterIssuer | `Issuer` |
| `rest.gatewayAPI.enabled` | Flag to expose the REST endpoint via Gateway API | `false` | | `tls.certManager.certificate.issuerRef.name` | Name of the issuer to use. If unset, it will use the name of the built in issuer | `""` |
| `rest.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-rest` | | `tls.rest.enabled` | Enable the REST listener served with the certificate from disk | `false` |
| `rest.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` | | `tls.rest.port` | Container port for the REST listener served with the certificate from disk | `8444` |
| `rest.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` | | `tls.rest.service.type` | Service type | `ClusterIP` |
| `rest.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` | | `tls.rest.service.port` | port for the service | `443` |
| `rest.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` | | `tls.rest.service.annotations` | Annotations for service resource | `{}` |
| `rest.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` | | `tls.rest.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `rest.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` | | `tls.rest.ingress.enabled` | Flag to enable ingress | `false` |
| `grpc.enabled` | Enable the grpc service | `false` | | `tls.rest.ingress.className` | Ingress class name | `""` |
| `grpc.service.type` | Service type | `ClusterIP` | | `tls.rest.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `grpc.service.port` | port for the service | `443` | | `tls.rest.ingress.annotations` | Annotations for ingress object | `{}` |
| `grpc.service.annotations` | Annotations for service resource | `{}` | | `tls.rest.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-rest` |
| `grpc.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | | `tls.rest.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `grpc.ingress.enabled` | Flag to enable ingress | `false` | | `tls.rest.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `grpc.ingress.className` | Ingress class name | `""` | | `tls.rest.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `grpc.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` | | `tls.rest.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `grpc.ingress.annotations` | Annotations for ingress object | `{}` | | `tls.rest.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-rest` |
| `grpc.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-grpc` | | `tls.rest.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` |
| `grpc.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` | | `tls.rest.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `grpc.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` | | `tls.rest.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `grpc.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` | | `tls.rest.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `grpc.gatewayAPI.enabled` | Flag to expose the gRPC endpoint via Gateway API | `false` | | `tls.rest.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `grpc.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-grpc` | | `tls.rest.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` |
| `grpc.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` | | `tls.grpc.enabled` | Enable the gRPC listener served with the certificate from disk | `false` |
| `grpc.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` | | `tls.grpc.port` | Container port for the gRPC listener served with the certificate from disk | `8443` |
| `grpc.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` | | `tls.grpc.service.type` | Service type | `ClusterIP` |
| `grpc.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` | | `tls.grpc.service.port` | port for the service | `443` |
| `grpc.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` | | `tls.grpc.service.annotations` | Annotations for service resource | `{}` |
| `grpc.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` | | `tls.grpc.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `tools.kubectl.image.registry` | The OCI registry to pull the image from | `registry.k8s.io` | | `tls.grpc.ingress.enabled` | Flag to enable ingress | `false` |
| `tools.kubectl.image.repository` | The repository within the registry | `kubectl` | | `tls.grpc.ingress.className` | Ingress class name | `""` |
| `tools.kubectl.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `tls.grpc.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `tools.kubectl.image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `tls.grpc.ingress.annotations` | Annotations for ingress object | `{}` |
| `clusterRole.create` | create a k8s cluster role to allow access to token reviews and oidc discovery | `true` | | `tls.grpc.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-grpc` |
| `server.address` | Address for Spire server | `""` | | `tls.grpc.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `server.port` | Port number for Spire server | `443` | | `tls.grpc.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `server.namespaceOverride` | Override the namespace for Spire server | `""` | | `tls.grpc.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `server.nameOverride` | Override the name for Spire server. Should only be changed when building your own nested chart to ensure names align. | `""` | | `tls.grpc.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `tls.grpc.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-grpc` |
| `tls.grpc.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` |
| `tls.grpc.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `tls.grpc.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `tls.grpc.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `tls.grpc.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `tls.grpc.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` |
| `spiffe.rest.enabled` | Enable the REST listener served with this deployment's own X509-SVID | `true` |
| `spiffe.rest.port` | Container port for the REST listener served with this deployment's own X509-SVID | `8544` |
| `spiffe.rest.service.type` | Service type | `ClusterIP` |
| `spiffe.rest.service.port` | port for the service | `443` |
| `spiffe.rest.service.annotations` | Annotations for service resource | `{}` |
| `spiffe.rest.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spiffe.rest.ingress.enabled` | Flag to enable ingress | `false` |
| `spiffe.rest.ingress.className` | Ingress class name | `""` |
| `spiffe.rest.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spiffe.rest.ingress.annotations` | Annotations for ingress object | `{}` |
| `spiffe.rest.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-rest-spiffe` |
| `spiffe.rest.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spiffe.rest.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spiffe.rest.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spiffe.rest.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spiffe.rest.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-rest-spiffe` |
| `spiffe.rest.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spiffe.rest.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spiffe.rest.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spiffe.rest.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `spiffe.grpc.enabled` | Enable the gRPC listener served with this deployment's own X509-SVID | `false` |
| `spiffe.grpc.port` | Container port for the gRPC listener served with this deployment's own X509-SVID | `8543` |
| `spiffe.grpc.service.type` | Service type | `ClusterIP` |
| `spiffe.grpc.service.port` | port for the service | `443` |
| `spiffe.grpc.service.annotations` | Annotations for service resource | `{}` |
| `spiffe.grpc.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spiffe.grpc.ingress.enabled` | Flag to enable ingress | `false` |
| `spiffe.grpc.ingress.className` | Ingress class name | `""` |
| `spiffe.grpc.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spiffe.grpc.ingress.annotations` | Annotations for ingress object | `{}` |
| `spiffe.grpc.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead. | `spire-identity-exchange-grpc-spiffe` |
| `spiffe.grpc.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spiffe.grpc.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spiffe.grpc.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spiffe.grpc.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spiffe.grpc.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-grpc-spiffe` |
| `spiffe.grpc.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spiffe.grpc.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spiffe.grpc.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spiffe.grpc.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `tools.kubectl.image.registry` | The OCI registry to pull the image from | `registry.k8s.io` |
| `tools.kubectl.image.repository` | The repository within the registry | `kubectl` |
| `tools.kubectl.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `tools.kubectl.image.tag` | Overrides the image tag whose default is the chart appVersion | `""` |
| `clusterRole.create` | create a k8s cluster role to allow access to token reviews and oidc discovery | `true` |
| `server.address` | Address for Spire server | `""` |
| `server.port` | Port number for Spire server | `443` |
| `server.namespaceOverride` | Override the namespace for Spire server | `""` |
| `server.nameOverride` | Override the name for Spire server. Should only be changed when building your own nested chart to ensure names align. | `""` |
@@ -1,14 +0,0 @@
spire-identity-exchange:
enabled: true
tls:
externalSecret:
enabled: true
secretName: spire-identity-exchange
auth:
plugins:
- plugin: k8s_psat
config:
audiences:
- spire-identity-exchange
allowedServiceAccounts:
- default/default
@@ -92,6 +92,64 @@ Create the name of the service account to use
{{- printf "/spiffe-workload-api/%s" .Values.agentSocketName }} {{- printf "/spiffe-workload-api/%s" .Values.agentSocketName }}
{{- end }} {{- end }}
{{/*
Volume name for an extra SPIFFE CSI driver. Driver names are DNS subdomains and may
contain dots, which a volume name (a DNS-1123 label) may not, so squash every run of
non-alphanumeric characters down to a single dash.
Args: the driver name as a string
*/}}
{{- define "spire-identity-exchange.csi-volume-name" -}}
{{- printf "spiffe-workload-api-%s" (trimAll "-" (regexReplaceAll "[^a-z0-9]+" (lower .) "-")) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Path to the SPIRE Agent workload socket one auth plugin should talk to. A plugin that
names no driver of its own, or names the one the exchange itself uses, gets the socket
already mounted for the pod; anything else gets its own mount under /spiffe-workload-apis.
Args: dict "root" <root context> "driver" <csi driver name, may be empty>
*/}}
{{- define "spire-identity-exchange.plugin-workload-api-socket-path" -}}
{{- $root := .root }}
{{- $driver := .driver | default "" }}
{{- if or (eq $driver "") (eq $driver $root.Values.csiDriverName) }}
{{- include "spire-identity-exchange.workload-api-socket-path" $root }}
{{- else }}
{{- printf "/spiffe-workload-apis/%s/%s" $driver $root.Values.agentSocketName }}
{{- end }}
{{- end }}
{{/*
The CSI drivers this release must mount in addition to the pod's own, collected from the
enabled spiffe auth plugins. Deduplicated, so two plugins naming the same driver share one
volume. Returns JSON of driver name -> volume name; callers pipe it through fromJson.
*/}}
{{- define "spire-identity-exchange.extra-csi-drivers" -}}
{{- $root := . }}
{{- $drivers := dict }}
{{- $volumeNames := dict }}
{{- range $name, $config := .Values.auth.plugins }}
{{- $config = $config | default dict }}
{{- if ne (dig "enabled" true $config) false }}
{{- $pluginType := include "spire-identity-exchange.plugin-type" (dict "root" $root "name" $name "config" $config) }}
{{- $driver := dig "csiDriverName" "" $config }}
{{- if and (eq $pluginType "spiffe") (not (empty $driver)) }}
{{- if not (kindIs "string" $driver) }}
{{- fail (printf "auth.plugins.%s.csiDriverName: expected string, got %s" $name (kindOf $driver)) }}
{{- end }}
{{- if ne $driver $root.Values.csiDriverName }}
{{- $volumeName := include "spire-identity-exchange.csi-volume-name" $driver }}
{{- if and (hasKey $volumeNames $volumeName) (ne (index $volumeNames $volumeName) $driver) }}
{{- fail (printf "auth.plugins.%s.csiDriverName: %q and %q both reduce to the volume name %q. Volume names allow only lowercase alphanumerics and dashes, so these two drivers cannot be told apart; rename one so they differ by more than punctuation." $name $driver (index $volumeNames $volumeName) $volumeName) }}
{{- end }}
{{- $_ := set $volumeNames $volumeName $driver }}
{{- $_ := set $drivers $driver $volumeName }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- $drivers | toJson }}
{{- end }}
{{- define "spire-identity-exchange.podSecurityContext" -}} {{- define "spire-identity-exchange.podSecurityContext" -}}
{{- $podSecurityContext := include "spire-lib.podsecuritycontext" . | fromYaml }} {{- $podSecurityContext := include "spire-lib.podsecuritycontext" . | fromYaml }}
{{- $openshift := ((.Values).global).openshift | default false }} {{- $openshift := ((.Values).global).openshift | default false }}
@@ -131,3 +189,57 @@ Create the name of the service account to use
{{ .Release.Name }}-server.{{ include "spire-identity-exchange.server.namespace" . }} {{ .Release.Name }}-server.{{ include "spire-identity-exchange.server.namespace" . }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- define "spire-identity-exchange.plugin-type" }}
{{- $type := .name }}
{{- with .config.plugin }}
{{- $type = . }}
{{- end }}
{{- if not (has $type (list "k8s_psat" "spiffe" "github" "gitlab" )) }}
{{- fail (printf "Unknown plugin type specified: %s" $type) }}
{{- end }}
{{- printf "%s" $type }}
{{- end }}
{{/*
Validate one plugin's config block against the option table for its type.
Emits nothing; only fails.
Args: dict "name" <instance name> "type" <plugin type> "config" <config map>
"options" <dict of option name -> "string" | "[]string" | "bool">
*/}}
{{- define "spire-identity-exchange.check-plugin-options" }}
{{- $ctx := . }}
{{- $valid := keys $ctx.options | sortAlpha | join ", " }}
{{- range $key, $val := $ctx.config }}
{{- if not (hasKey $ctx.options $key) }}
{{- fail (printf "auth.plugins.%s.config: %q is not a valid option for plugin type %q (valid options: %s). Use auth.unsupportedBuiltInPlugins to pass through options this chart does not model." $ctx.name $key $ctx.type $valid) }}
{{- end }}
{{- $want := index $ctx.options $key }}
{{- if eq $want "[]string" }}
{{- if not (kindIs "slice" $val) }}
{{- fail (printf "auth.plugins.%s.config.%s: expected a list of strings, got %s" $ctx.name $key (kindOf $val)) }}
{{- end }}
{{- range $val }}
{{- if not (kindIs "string" .) }}
{{- fail (printf "auth.plugins.%s.config.%s: every entry must be a string, got %s" $ctx.name $key (kindOf .)) }}
{{- end }}
{{- end }}
{{- else if not (kindIs $want $val) }}
{{- fail (printf "auth.plugins.%s.config.%s: expected %s, got %s" $ctx.name $key $want (kindOf $val)) }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Fail if any of the named options is absent or empty. Emits nothing.
Args: dict "name" <instance name> "type" <plugin type> "config" <config map>
"required" <list of option names>
*/}}
{{- define "spire-identity-exchange.check-plugin-required" }}
{{- $ctx := . }}
{{- range $ctx.required }}
{{- if empty (index $ctx.config .) }}
{{- fail (printf "auth.plugins.%s.config.%s is required for plugin type %q" $ctx.name . $ctx.type) }}
{{- end }}
{{- end }}
{{- end }}
@@ -4,12 +4,18 @@ dnsNames:
{{- if ne (len .Values.tls.certManager.certificate.dnsNames) 0 }} {{- if ne (len .Values.tls.certManager.certificate.dnsNames) 0 }}
{{- toYaml .Values.tls.certManager.certificate.dnsNames | nindent 4 }} {{- toYaml .Values.tls.certManager.certificate.dnsNames | nindent 4 }}
{{- else }} {{- else }}
{{- if .Values.rest.enabled }} {{- $hosts := list }}
- {{ include "spire-lib.ingress-calculated-name" (dict "ingress" .Values.rest.ingress "Values" .Values) }} {{- range $l := list .Values.tls.rest .Values.tls.grpc }}
{{- end }} {{- if $l.enabled }}
{{- if .Values.grpc.enabled }} {{- if $l.ingress.enabled }}
- {{ include "spire-lib.ingress-calculated-name" (dict "ingress" .Values.grpc.ingress "Values" .Values) }} {{- $hosts = append $hosts (include "spire-lib.ingress-calculated-name" (dict "ingress" $l.ingress "Values" $.Values) | trim) }}
{{- end }}
{{- if $l.gatewayAPI.enabled }}
{{- $hosts = append $hosts (include "spire-lib.ingress-calculated-name" (dict "ingress" (dict "host" $l.gatewayAPI.host) "Values" $.Values) | trim) }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- toYaml (uniq $hosts) | nindent 4 }}
{{- end }} {{- end }}
issuerRef: issuerRef:
{{- with .Values.tls.certManager.certificate.issuerRef.group }} {{- with .Values.tls.certManager.certificate.issuerRef.group }}
@@ -19,7 +25,7 @@ issuerRef:
name: {{ default $fullName .Values.tls.certManager.certificate.issuerRef.name }} name: {{ default $fullName .Values.tls.certManager.certificate.issuerRef.name }}
secretName: {{ $fullName }}-cert secretName: {{ $fullName }}-cert
{{- end }} {{- end }}
{{- if .Values.tls.certManager.enabled }} {{- if and .Values.tls.certManager.enabled (or .Values.tls.rest.enabled .Values.tls.grpc.enabled) }}
--- ---
apiVersion: cert-manager.io/v1 apiVersion: cert-manager.io/v1
kind: Certificate kind: Certificate
@@ -1,20 +1,47 @@
{{- $tlsCount := 0 }} {{- $fileTLS := or .Values.tls.rest.enabled .Values.tls.grpc.enabled }}
{{- if .Values.tls.externalSecret.enabled }} {{- if $fileTLS }}
{{- $tlsCount = add $tlsCount 1 }} {{- $tlsCount := 0 }}
{{- if .Values.tls.externalSecret.enabled }}
{{- $tlsCount = add $tlsCount 1 }}
{{- end }}
{{- if .Values.tls.certManager.enabled }}
{{- $tlsCount = add $tlsCount 1 }}
{{- end }}
{{- if ne $tlsCount 1 }}
{{- fail "You must have one and only one TLS configuration enabled (tls.externalSecret or tls.certManager) when a tls listener is enabled" }}
{{- end }}
{{- if and .Values.tls.certManager.enabled (eq (len .Values.tls.certManager.certificate.dnsNames) 0) }}
{{- if and .Values.tls.rest.enabled (not (or .Values.tls.rest.ingress.enabled .Values.tls.rest.gatewayAPI.enabled)) }}
{{- fail "tls.certManager takes the certificate hostname from the exposure: enable tls.rest.ingress or tls.rest.gatewayAPI, or set tls.certManager.certificate.dnsNames" }}
{{- end }}
{{- if and .Values.tls.grpc.enabled (not (or .Values.tls.grpc.ingress.enabled .Values.tls.grpc.gatewayAPI.enabled)) }}
{{- fail "tls.certManager takes the certificate hostname from the exposure: enable tls.grpc.ingress or tls.grpc.gatewayAPI, or set tls.certManager.certificate.dnsNames" }}
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if .Values.tls.certManager.enabled }} {{- if kindIs "slice" .Values.auth.plugins }}
{{- $tlsCount = add $tlsCount 1 }} {{- fail "auth.plugins is a mapping keyed by plugin name, not a list: replace each `- plugin: k8s_psat` entry with a `k8s_psat:` key holding its config" }}
{{- end }} {{- end }}
{{- if ne $tlsCount 1 }} {{- if kindIs "slice" .Values.auth.stacks }}
{{- fail "You must have one and only one TLS configuration enabled" }} {{- fail "auth.stacks is a mapping keyed by stack name, not a list: replace each `- name: foo` / `plugins: [...]` entry with a `foo:` key holding `plugins: [...]`" }}
{{- end }} {{- end }}
{{- if lt (len .Values.auth.plugins) 1 }} {{- if lt (len .Values.auth.plugins) 1 }}
{{- fail "You must have at least one auth plugin defined" }} {{- fail "You must have at least one auth plugin defined" }}
{{- end }} {{- end }}
{{- if not (or .Values.rest.enabled .Values.grpc.enabled) }} {{- if not (or $fileTLS .Values.spiffe.rest.enabled .Values.spiffe.grpc.enabled) }}
{{- fail "You must have rest and/or grpc enabled" }} {{- fail "You must enable at least one listener: tls.rest, tls.grpc, spiffe.rest or spiffe.grpc" }}
{{- end }} {{- end }}
{{- $trustDomain := include "spire-lib.trust-domain" . }} {{- $trustDomain := include "spire-lib.trust-domain" . }}
{{- $root := . }}
{{- $enabledPlugins := list }}
{{- range $name, $config := .Values.auth.plugins }}
{{- if ne (dig "enabled" true ($config | default dict)) false }}
{{- $enabledPlugins = append $enabledPlugins $name }}
{{- end }}
{{- end }}
{{- if lt (len $enabledPlugins) 1 }}
{{- fail "Every auth plugin is disabled: at least one entry in auth.plugins must have enabled: true" }}
{{- end }}
{{- include "spire-lib.check-strict-mode" (list . "trustDomain must be set" (eq $trustDomain "example.org"))}} {{- include "spire-lib.check-strict-mode" (list . "trustDomain must be set" (eq $trustDomain "example.org"))}}
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
@@ -28,23 +55,147 @@ metadata:
data: data:
six.conf: | six.conf: |
name: spire-identity-exchange name: spire-identity-exchange
logLevel: info logLevel: {{ .Values.config.logLevel }}
server: server:
port: 8443 metricsPort: {{ .Values.telemetry.prometheus.port }}
restPort: 8444
metricsPort: 4950
tls: tls:
{{- if $fileTLS }}
certFile: /secret/tls.crt certFile: /secret/tls.crt
keyFile: /secret/tls.key keyFile: /secret/tls.key
{{- end }}
grpc:
enable: {{ .Values.tls.grpc.enabled }}
port: {{ .Values.tls.grpc.port }}
rest:
enable: {{ .Values.tls.rest.enabled }}
port: {{ .Values.tls.rest.port }}
spiffe:
grpc:
enable: {{ .Values.spiffe.grpc.enabled }}
port: {{ .Values.spiffe.grpc.port }}
rest:
enable: {{ .Values.spiffe.rest.enabled }}
port: {{ .Values.spiffe.rest.port }}
spire: spire:
agentWorkloadSocketPath: /spiffe-workload-api/spire-agent.sock agentWorkloadSocketPath: {{ include "spire-identity-exchange.workload-api-socket-path" . }}
agentDelegatedSocketPath: /agent/admin.sock agentDelegatedSocketPath: /agent/admin.sock
trustDomain: {{ $trustDomain }} trustDomain: {{ $trustDomain }}
svidTTL: 1h svidTTL: 1h
auth: auth:
passthroughPlugins: {{ .Values.auth.passthroughPlugins }}
plugins: plugins:
{{- toYaml .Values.auth.plugins | nindent 8 }} {{- range $name, $config := .Values.auth.plugins }}
{{ with .Values.auth.stacks }} {{- if has $name $enabledPlugins }}
{{- $pluginType := include "spire-identity-exchange.plugin-type" (dict "root" $root "name" $name "config" $config) }}
{{- $cfg := $config.config | default dict }}
{{- if hasKey ($config | default dict) "csiDriverName" }}
{{- if ne $pluginType "spiffe" }}
{{- fail (printf "auth.plugins.%s: csiDriverName is only supported on plugins of type \"spiffe\". Plugin type %q does not talk to a SPIRE Agent workload socket, so there is nothing to mount the driver for." $name $pluginType) }}
{{- end }}
{{- if not (kindIs "string" $config.csiDriverName) }}
{{- fail (printf "auth.plugins.%s.csiDriverName: expected string, got %s" $name (kindOf $config.csiDriverName)) }}
{{- end }}
{{- end }}
{{ if eq $name "k8sPSAT" }}k8s_psat{{ else }}{{ $name | quote }}{{ end }}:
{{- with $config.plugin }}
plugin: {{ . | quote }}
{{- end }}
config:
{{- if eq $pluginType "k8s_psat" }}
{{- if hasKey $cfg "kubeconfig" }}
{{- fail (printf "auth.plugins.%s.config: kubeconfig is not supported by this chart. In a pod, spire-identity-exchange always authenticates to the Kubernetes API with the in-cluster credentials of its own ServiceAccount and ignores a kubeconfig file, so pointing it at another cluster would silently validate tokens against the local one instead." $name) }}
{{- end }}
{{- $_ := include "spire-identity-exchange.check-plugin-options" (dict "name" $name "type" $pluginType "config" $cfg "options" (dict
"clusterName" "string"
"audiences" "[]string"
"allowedNamespaces" "[]string"
"allowedServiceAccounts" "[]string"
"jwksCheck" "bool"
"tokenReview" "bool")) }}
{{- $jwksCheck := ne (dig "jwksCheck" true $cfg) false }}
{{- $tokenReview := ne (dig "tokenReview" true $cfg) false }}
{{- if not (or $jwksCheck $tokenReview) }}
{{- fail (printf "auth.plugins.%s.config: jwksCheck and tokenReview cannot both be false; at least one validation stage must remain active" $name) }}
{{- end }}
{{- if $jwksCheck }}
{{- $_ := include "spire-identity-exchange.check-plugin-required" (dict "name" $name "type" $pluginType "config" $cfg "required" (list "audiences")) }}
{{- end }}
{{- if and (empty $cfg.allowedNamespaces) (empty $cfg.allowedServiceAccounts) }}
{{- fail (printf "auth.plugins.%s.config: at least one of allowedNamespaces or allowedServiceAccounts must be set" $name) }}
{{- end }}
{{- toYaml $config.config | nindent 12 }}
{{- else if eq $pluginType "spiffe" }}
{{- if hasKey $cfg "agentWorkloadSocketPath" }}
{{- fail (printf "auth.plugins.%s.config: agentWorkloadSocketPath is set by this chart, not in values. The SPIRE Agent workload socket is mounted from the SPIFFE CSI driver and the path is filled in automatically when connectWithTrustBundle is true." $name) }}
{{- end }}
{{- $_ := include "spire-identity-exchange.check-plugin-options" (dict "name" $name "type" $pluginType "config" $cfg "options" (dict
"issuerURL" "string"
"discoveryURL" "string"
"trustDomain" "string"
"audiences" "[]string"
"pathPatterns" "[]string"
"connectWithTrustBundle" "bool")) }}
{{- $_ := include "spire-identity-exchange.check-plugin-required" (dict "name" $name "type" $pluginType "config" $cfg "required" (list "issuerURL" "audiences" "trustDomain" "pathPatterns")) }}
{{- $driver := dig "csiDriverName" "" ($config | default dict) }}
{{- if and (not (empty $driver)) (not $cfg.connectWithTrustBundle) }}
{{- fail (printf "auth.plugins.%s: csiDriverName is only meaningful when config.connectWithTrustBundle is true; the SPIRE Agent workload socket is not used otherwise." $name) }}
{{- end }}
{{- $keySource := dig "keySource" "oidc" ($config | default dict) }}
{{- if not (has $keySource (list "oidc" "oidcLocal")) }}
{{- fail (printf "auth.plugins.%s.keySource: %q is not valid; must be oidc or oidcLocal" $name $keySource) }}
{{- end }}
{{- $effective := $cfg }}
{{- if $cfg.connectWithTrustBundle }}
{{- $effective = merge (dict "agentWorkloadSocketPath" (include "spire-identity-exchange.plugin-workload-api-socket-path" (dict "root" $root "driver" $driver))) $cfg }}
{{- end }}
{{- if and (eq $keySource "oidcLocal") (empty $cfg.discoveryURL) }}
{{- $effective = merge (dict "discoveryURL" (printf "https://%s-spiffe-oidc-discovery-provider" $root.Release.Name)) $effective }}
{{- end }}
{{- toYaml $effective | nindent 12 }}
{{- else if eq $pluginType "github" }}
{{- $_ := include "spire-identity-exchange.check-plugin-options" (dict "name" $name "type" $pluginType "config" $cfg "options" (dict
"issuerURL" "string"
"audiences" "[]string"
"allowedRepositoryOwners" "[]string"
"allowedRepositories" "[]string")) }}
{{- $_ := include "spire-identity-exchange.check-plugin-required" (dict "name" $name "type" $pluginType "config" $cfg "required" (list "audiences")) }}
{{- if and (empty $cfg.allowedRepositoryOwners) (empty $cfg.allowedRepositories) }}
{{- fail (printf "auth.plugins.%s.config: at least one of allowedRepositoryOwners or allowedRepositories must be set" $name) }}
{{- end }}
{{- toYaml $config.config | nindent 12 }}
{{- else if eq $pluginType "gitlab" }}
{{- $_ := include "spire-identity-exchange.check-plugin-options" (dict "name" $name "type" $pluginType "config" $cfg "options" (dict
"issuerURL" "string"
"audiences" "[]string"
"allowedNamespacePaths" "[]string"
"allowedProjectPaths" "[]string")) }}
{{- $_ := include "spire-identity-exchange.check-plugin-required" (dict "name" $name "type" $pluginType "config" $cfg "required" (list "audiences")) }}
{{- if and (empty $cfg.allowedNamespacePaths) (empty $cfg.allowedProjectPaths) }}
{{- fail (printf "auth.plugins.%s.config: at least one of allowedNamespacePaths or allowedProjectPaths must be set" $name) }}
{{- end }}
{{- toYaml $config.config | nindent 12 }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.auth.unsupportedBuiltInPlugins }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $stacks := dict }}
{{- range $stackName, $stack := .Values.auth.stacks }}
{{- if ne (dig "enabled" true ($stack | default dict)) false }}
{{- range $plugin := $stack.plugins }}
{{- if not (has $plugin $enabledPlugins) }}
{{- if hasKey $root.Values.auth.plugins $plugin }}
{{- fail (printf "auth.stacks.%s lists plugin %q, which is disabled. Set auth.plugins.%s.enabled: true or drop it from the stack; the exchange refuses to start when a stack names a plugin it did not load." $stackName $plugin $plugin) }}
{{- else }}
{{- fail (printf "auth.stacks.%s lists plugin %q, which is not defined in auth.plugins" $stackName $plugin) }}
{{- end }}
{{- end }}
{{- end }}
{{- $_ := set $stacks $stackName (omit $stack "enabled") }}
{{- end }}
{{- end }}
{{- with $stacks }}
stacks: stacks:
{{- toYaml . | nindent 8 }} {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}
@@ -55,8 +206,7 @@ data:
trust_domain = {{ $trustDomain | quote }} trust_domain = {{ $trustDomain | quote }}
server_address = {{ include "spire-identity-exchange.server-address" . | trim | quote }} server_address = {{ include "spire-identity-exchange.server-address" . | trim | quote }}
server_port = {{ .Values.server.port }} server_port = {{ .Values.server.port }}
trust_bundle_url = "http://localhost/trustbundle" trust_bundle_spiffe_workload_api = "unix://{{ include "spire-identity-exchange.workload-api-socket-path" . }}"
trust_bundle_unix_socket = "/trustbundle/socket"
rebootstrap_mode = "always" rebootstrap_mode = "always"
rebootstrap_delay = "5m" rebootstrap_delay = "5m"
@@ -80,7 +230,7 @@ data:
NodeAttestor "x509pop" { NodeAttestor "x509pop" {
plugin_data { plugin_data {
spiffe_endpoint_socket = "unix:///spiffe-workload-api/spire-agent.sock" spiffe_endpoint_socket = "unix://{{ include "spire-identity-exchange.workload-api-socket-path" . }}"
} }
} }
@@ -1,5 +1,7 @@
{{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }} {{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }}
{{- $trustDomain := include "spire-lib.trust-domain" . }} {{- $trustDomain := include "spire-lib.trust-domain" . }}
{{- $fileTLS := or .Values.tls.rest.enabled .Values.tls.grpc.enabled }}
{{- $extraCSIDrivers := include "spire-identity-exchange.extra-csi-drivers" . | fromJson }}
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
@@ -43,38 +45,6 @@ spec:
securityContext: securityContext:
{{- include "spire-identity-exchange.podSecurityContext" . | nindent 8 }} {{- include "spire-identity-exchange.podSecurityContext" . | nindent 8 }}
initContainers: initContainers:
- name: spire-server-attestor
securityContext:
{{- include "spire-lib.securitycontext" . | nindent 12 }}
resources:
{{- toYaml .Values.spireServerAttestorSPIFFEWorkloadAPI.resources | nindent 12 }}
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.spireServerAttestorSPIFFEWorkloadAPI.image "global" .Values.global) }}
imagePullPolicy: {{ .Values.spireServerAttestorSPIFFEWorkloadAPI.image.pullPolicy }}
restartPolicy: Always
args:
- /trustbundle/socket
env:
- name: SPIFFE_ENDPOINT_SOCKET
value: "unix:///spiffe-workload-api/spire-agent.sock"
- name: SPIFFE_TRUST_DOMAIN
value: {{ $trustDomain }}
readinessProbe:
exec:
command:
- /ko-app/spire-server-attestor-spiffe-workload-api
- --healthcheck
- /trustbundle/socket
initialDelaySeconds: 5
periodSeconds: 30
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3
volumeMounts:
- name: spiffe-workload-api
mountPath: /spiffe-workload-api
readOnly: true
- name: trustbundle
mountPath: /trustbundle
- name: spire-agent - name: spire-agent
securityContext: securityContext:
{{- include "spire-lib.securitycontext" . | nindent 12 }} {{- include "spire-lib.securitycontext" . | nindent 12 }}
@@ -109,9 +79,6 @@ spec:
readOnly: true readOnly: true
- name: spire-agent-socket - name: spire-agent-socket
mountPath: /agent mountPath: /agent
- name: trustbundle
mountPath: /trustbundle
readOnly: true
- name: spire-agent-data - name: spire-agent-data
mountPath: /agent-data mountPath: /agent-data
containers: containers:
@@ -124,26 +91,49 @@ spec:
- -config - -config
- /etc/spire/identity-exchange/six.conf - /etc/spire/identity-exchange/six.conf
- -expand-env - -expand-env
{{- with .Values.extraEnv }}
env: env:
- name: SPIFFE_TRUST_DOMAIN
value: {{ $trustDomain | quote }}
- name: K8S_CLUSTER_NAME
value: {{ include "spire-lib.cluster-name" . | trim | quote }}
- name: SPIFFE_JWT_ISSUER
value: {{ include "spire-lib.jwt-issuer" . | trim | quote }}
{{- with .Values.extraEnv }}
{{- . | toYaml | nindent 12 }} {{- . | toYaml | nindent 12 }}
{{- end }} {{- end }}
ports: ports:
{{- if .Values.rest.enabled }} {{- if .Values.tls.rest.enabled }}
- containerPort: 8444 - containerPort: {{ .Values.tls.rest.port }}
name: rest name: rest
{{- end }} {{- end }}
{{- if .Values.grpc.enabled }} {{- if .Values.tls.grpc.enabled }}
- containerPort: 8443 - containerPort: {{ .Values.tls.grpc.port }}
name: grpc name: grpc
{{- end }} {{- end }}
{{- if .Values.spiffe.rest.enabled }}
- containerPort: {{ .Values.spiffe.rest.port }}
name: rest-spiffe
{{- end }}
{{- if .Values.spiffe.grpc.enabled }}
- containerPort: {{ .Values.spiffe.grpc.port }}
name: grpc-spiffe
{{- end }}
- containerPort: {{ .Values.telemetry.prometheus.port }}
name: prom
volumeMounts: volumeMounts:
- name: spiffe-workload-api - name: spiffe-workload-api
mountPath: {{ include "spire-identity-exchange.workload-api-socket-path" . | dir }} mountPath: {{ include "spire-identity-exchange.workload-api-socket-path" . | dir }}
readOnly: true readOnly: true
{{- range $driver, $volumeName := $extraCSIDrivers }}
- name: {{ $volumeName }}
mountPath: /spiffe-workload-apis/{{ $driver }}
readOnly: true
{{- end }}
{{- if $fileTLS }}
- name: certdir - name: certdir
mountPath: /secret mountPath: /secret
readOnly: true readOnly: true
{{- end }}
- name: spire-identity-exchange-config - name: spire-identity-exchange-config
mountPath: /etc/spire/identity-exchange/six.conf mountPath: /etc/spire/identity-exchange/six.conf
subPath: six.conf subPath: six.conf
@@ -168,6 +158,13 @@ spec:
csi: csi:
driver: "{{ .Values.csiDriverName }}" driver: "{{ .Values.csiDriverName }}"
readOnly: true readOnly: true
{{- range $driver, $volumeName := $extraCSIDrivers }}
- name: {{ $volumeName }}
csi:
driver: "{{ $driver }}"
readOnly: true
{{- end }}
{{- if $fileTLS }}
- name: certdir - name: certdir
{{- if .Values.tls.externalSecret.enabled }} {{- if .Values.tls.externalSecret.enabled }}
secret: secret:
@@ -176,12 +173,11 @@ spec:
secret: secret:
secretName: {{ include "spire-identity-exchange.fullname" . }}-cert secretName: {{ include "spire-identity-exchange.fullname" . }}-cert
{{- end }} {{- end }}
{{- end }}
- name: spire-agent-socket - name: spire-agent-socket
emptyDir: {} emptyDir: {}
- name: spire-agent-data - name: spire-agent-data
emptyDir: {} emptyDir: {}
- name: trustbundle
emptyDir: {}
- name: spire-identity-exchange-config - name: spire-identity-exchange-config
configMap: configMap:
name: {{ include "spire-identity-exchange.fullname" . }} name: {{ include "spire-identity-exchange.fullname" . }}
@@ -1,13 +0,0 @@
{{- if .Values.grpc.gatewayAPI.enabled -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.grpc.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.grpc.gatewayAPI
"name" (printf "%s-grpc" (include "spire-identity-exchange.fullname" .))
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" (printf "%s-grpc" (include "spire-identity-exchange.fullname" .))
"port" .Values.grpc.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -10,7 +10,7 @@ solvers:
- http01: - http01:
ingress: {} ingress: {}
{{- end }} {{- end }}
{{- if and .Values.tls.certManager.enabled .Values.tls.certManager.issuer.create }} {{- if and .Values.tls.certManager.enabled .Values.tls.certManager.issuer.create (or .Values.tls.rest.enabled .Values.tls.grpc.enabled) }}
apiVersion: cert-manager.io/v1 apiVersion: cert-manager.io/v1
kind: Issuer kind: Issuer
metadata: metadata:
@@ -0,0 +1,28 @@
{{- if (dig "telemetry" "prometheus" "podMonitor" "enabled" .Values.telemetry.prometheus.podMonitor.enabled .Values.global) }}
{{- $namespace := include "spire-identity-exchange.podMonitor.namespace" . }}
{{- $podNamespace := include "spire-identity-exchange.namespace" . }}
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: {{ include "spire-identity-exchange.fullname" . }}
namespace: {{ $namespace | quote }}
labels:
{{- include "spire-identity-exchange.labels" . | nindent 4 }}
{{- if ne (len (dig "telemetry" "prometheus" "podMonitor" "labels" (dict) .Values.global)) 0 }}
{{- .Values.global.telemetry.prometheus.podMonitor.labels | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.telemetry.prometheus.podMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "spire-identity-exchange.selectorLabels" . | nindent 6 }}
podMetricsEndpoints:
- port: prom
{{- if ne $namespace $podNamespace }}
namespaceSelector:
matchNames:
- {{ $podNamespace | quote }}
{{- end }}
{{- end }}
@@ -1,13 +0,0 @@
{{- if .Values.rest.gatewayAPI.enabled -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.rest.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.rest.gatewayAPI
"name" (printf "%s-rest" (include "spire-identity-exchange.fullname" .))
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" (printf "%s-rest" (include "spire-identity-exchange.fullname" .))
"port" .Values.rest.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -0,0 +1,15 @@
{{- if and .Values.spiffe.grpc.enabled .Values.spiffe.grpc.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-grpc-spiffe" (include "spire-identity-exchange.fullname" .) -}}
{{/* Passthrough only. This backend serves an X509-SVID, whose only SAN is a
spiffe:// URI, so a BackendTLSPolicy hostname check could never match. */}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spiffe.grpc.gatewayAPI
"name" $fullName
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" $fullName
"port" .Values.spiffe.grpc.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" "TLSRoute"
"backendTLS" false) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.spiffe.grpc.enabled .Values.spiffe.grpc.ingress.enabled -}}
{{- $port := .Values.spiffe.grpc.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spiffe.grpc.ingress) }}
{{- $fullName := printf "%s-grpc-spiffe" (include "spire-identity-exchange.fullname" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spiffe.grpc.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spiffe.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spiffe.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-identity-exchange.namespace" . }}
labels:
{{ include "spire-identity-exchange.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spiffe.grpc.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if .Values.spiffe.grpc.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-identity-exchange.fullname" . }}-grpc-spiffe
namespace: {{ include "spire-identity-exchange.namespace" . }}
{{- with .Values.spiffe.grpc.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spiffe.grpc.service.type }}
{{- if and (eq .Values.spiffe.grpc.service.type "LoadBalancer") .Values.spiffe.grpc.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spiffe.grpc.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spiffe.grpc.service.port }}
targetPort: grpc-spiffe
protocol: TCP
selector:
{{- include "spire-identity-exchange.selectorLabels" . | nindent 4 }}
{{- end }}
@@ -0,0 +1,15 @@
{{- if and .Values.spiffe.rest.enabled .Values.spiffe.rest.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-rest-spiffe" (include "spire-identity-exchange.fullname" .) -}}
{{/* Passthrough only. This backend serves an X509-SVID, whose only SAN is a
spiffe:// URI, so a BackendTLSPolicy hostname check could never match. */}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spiffe.rest.gatewayAPI
"name" $fullName
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" $fullName
"port" .Values.spiffe.rest.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" "TLSRoute"
"backendTLS" false) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.spiffe.rest.enabled .Values.spiffe.rest.ingress.enabled -}}
{{- $port := .Values.spiffe.rest.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spiffe.rest.ingress) }}
{{- $fullName := printf "%s-rest-spiffe" (include "spire-identity-exchange.fullname" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spiffe.rest.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spiffe.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spiffe.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-identity-exchange.namespace" . }}
labels:
{{ include "spire-identity-exchange.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spiffe.rest.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if .Values.spiffe.rest.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-identity-exchange.fullname" . }}-rest-spiffe
namespace: {{ include "spire-identity-exchange.namespace" . }}
{{- with .Values.spiffe.rest.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spiffe.rest.service.type }}
{{- if and (eq .Values.spiffe.rest.service.type "LoadBalancer") .Values.spiffe.rest.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spiffe.rest.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spiffe.rest.service.port }}
targetPort: rest-spiffe
protocol: TCP
selector:
{{- include "spire-identity-exchange.selectorLabels" . | nindent 4 }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if and .Values.tls.grpc.enabled .Values.tls.grpc.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-grpc" (include "spire-identity-exchange.fullname" .) -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.tls.grpc.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.tls.grpc.gatewayAPI
"name" $fullName
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" $fullName
"port" .Values.tls.grpc.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -1,20 +1,20 @@
{{- if .Values.grpc.ingress.enabled -}} {{- if and .Values.tls.grpc.enabled .Values.tls.grpc.ingress.enabled -}}
{{- $port := .Values.grpc.service.port }} {{- $port := .Values.tls.grpc.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.grpc.ingress) }} {{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.tls.grpc.ingress) }}
{{- $fullName := printf "%s-grpc" (include "spire-identity-exchange.fullname" .) }} {{- $fullName := printf "%s-grpc" (include "spire-identity-exchange.fullname" .) }}
{{- $path := "/" }} {{- $path := "/" }}
{{- $pathType := "Prefix" }} {{- $pathType := "Prefix" }}
{{- $tlsSection := true }} {{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.grpc.ingress.annotations }} {{- $annotations := deepCopy .Values.tls.grpc.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }} {{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not (and .Values.grpc.ingress.enabled .Values.grpc.ingress.tlsSecret) }} {{- if not .Values.tls.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }} {{- end }}
{{- else if eq $ingressControllerType "openshift" }} {{- else if eq $ingressControllerType "openshift" }}
{{- if and .Values.grpc.ingress.enabled .Values.grpc.ingress.tlsSecret }} {{- if .Values.tls.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }} {{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }} {{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }} {{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
@@ -35,5 +35,5 @@ metadata:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
spec: spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.grpc.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }} {{ include "spire-lib.ingress-spec" (dict "ingress" .Values.tls.grpc.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }} {{- end }}
@@ -1,21 +1,21 @@
{{- if .Values.grpc.enabled }} {{- if .Values.tls.grpc.enabled }}
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: {{ include "spire-identity-exchange.fullname" . }}-grpc name: {{ include "spire-identity-exchange.fullname" . }}-grpc
namespace: {{ include "spire-identity-exchange.namespace" . }} namespace: {{ include "spire-identity-exchange.namespace" . }}
{{- with .Values.service.annotations }} {{- with .Values.tls.grpc.service.annotations }}
annotations: annotations:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
spec: spec:
type: {{ .Values.grpc.service.type }} type: {{ .Values.tls.grpc.service.type }}
{{- if and (eq .Values.grpc.service.type "LoadBalancer") .Values.grpc.service.loadBalancerIP }} {{- if and (eq .Values.tls.grpc.service.type "LoadBalancer") .Values.tls.grpc.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.grpc.service.loadBalancerIP }} loadBalancerIP: {{ .Values.tls.grpc.service.loadBalancerIP }}
{{- end }} {{- end }}
ports: ports:
- name: https - name: https
port: {{ .Values.grpc.service.port }} port: {{ .Values.tls.grpc.service.port }}
targetPort: grpc targetPort: grpc
protocol: TCP protocol: TCP
selector: selector:
@@ -0,0 +1,14 @@
{{- if and .Values.tls.rest.enabled .Values.tls.rest.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-rest" (include "spire-identity-exchange.fullname" .) -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.tls.rest.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.tls.rest.gatewayAPI
"name" $fullName
"namespace" (include "spire-identity-exchange.namespace" .)
"svcName" $fullName
"port" .Values.tls.rest.service.port
"labels" (include "spire-identity-exchange.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -1,20 +1,20 @@
{{- if .Values.rest.ingress.enabled -}} {{- if and .Values.tls.rest.enabled .Values.tls.rest.ingress.enabled -}}
{{- $port := .Values.rest.service.port }} {{- $port := .Values.tls.rest.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.rest.ingress) }} {{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.tls.rest.ingress) }}
{{- $fullName := printf "%s-rest" (include "spire-identity-exchange.fullname" .) }} {{- $fullName := printf "%s-rest" (include "spire-identity-exchange.fullname" .) }}
{{- $path := "/" }} {{- $path := "/" }}
{{- $pathType := "Prefix" }} {{- $pathType := "Prefix" }}
{{- $tlsSection := true }} {{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.rest.ingress.annotations }} {{- $annotations := deepCopy .Values.tls.rest.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }} {{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not (and .Values.rest.ingress.enabled .Values.rest.ingress.tlsSecret) }} {{- if not .Values.tls.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }} {{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }} {{- end }}
{{- else if eq $ingressControllerType "openshift" }} {{- else if eq $ingressControllerType "openshift" }}
{{- if and .Values.rest.ingress.enabled .Values.rest.ingress.tlsSecret }} {{- if .Values.tls.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }} {{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }} {{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }} {{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
@@ -35,5 +35,5 @@ metadata:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
spec: spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.rest.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }} {{ include "spire-lib.ingress-spec" (dict "ingress" .Values.tls.rest.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }} {{- end }}
@@ -1,21 +1,21 @@
{{- if .Values.rest.enabled }} {{- if .Values.tls.rest.enabled }}
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: {{ include "spire-identity-exchange.fullname" . }}-rest name: {{ include "spire-identity-exchange.fullname" . }}-rest
namespace: {{ include "spire-identity-exchange.namespace" . }} namespace: {{ include "spire-identity-exchange.namespace" . }}
{{- with .Values.rest.service.annotations }} {{- with .Values.tls.rest.service.annotations }}
annotations: annotations:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
spec: spec:
type: {{ .Values.rest.service.type }} type: {{ .Values.tls.rest.service.type }}
{{- if and (eq .Values.rest.service.type "LoadBalancer") .Values.rest.service.loadBalancerIP }} {{- if and (eq .Values.tls.rest.service.type "LoadBalancer") .Values.tls.rest.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.rest.service.loadBalancerIP }} loadBalancerIP: {{ .Values.tls.rest.service.loadBalancerIP }}
{{- end }} {{- end }}
ports: ports:
- name: https - name: https
port: {{ .Values.rest.service.port }} port: {{ .Values.tls.rest.service.port }}
targetPort: rest targetPort: rest
protocol: TCP protocol: TCP
selector: selector:
+368 -199
View File
@@ -37,30 +37,6 @@ image:
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
tag: "" tag: ""
spireServerAttestorSPIFFEWorkloadAPI:
## @param spireServerAttestorSPIFFEWorkloadAPI.resources [object] Resource requests and limits
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# requests:
# cpu: 50m
# memory: 32Mi
# limits:
# cpu: 100m
# memory: 64Mi
image:
## @param spireServerAttestorSPIFFEWorkloadAPI.image.registry The OCI registry to pull the image from
## @param spireServerAttestorSPIFFEWorkloadAPI.image.repository The repository within the registry
## @param spireServerAttestorSPIFFEWorkloadAPI.image.pullPolicy The image pull policy
## @param spireServerAttestorSPIFFEWorkloadAPI.image.tag Overrides the image tag whose default is the chart appVersion
##
registry: ghcr.io
repository: spiffe/spire-server-attestor-spiffe-workload-api
pullPolicy: IfNotPresent
tag: ""
spireAgent: spireAgent:
## @param spireAgent.resources [object] Resource requests and limits ## @param spireAgent.resources [object] Resource requests and limits
resources: {} resources: {}
@@ -83,7 +59,7 @@ spireAgent:
registry: ghcr.io registry: ghcr.io
repository: spiffe/spire-agent repository: spiffe/spire-agent
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
tag: "1.15.2" tag: "1.15.3"
## @param extraEnv [array] Extra environment variables to add to the spire identity exchange ## @param extraEnv [array] Extra environment variables to add to the spire identity exchange
extraEnv: [] extraEnv: []
@@ -138,49 +114,25 @@ podAnnotations: {}
## @param podLabels [object] Labels to add to pods ## @param podLabels [object] Labels to add to pods
podLabels: {} podLabels: {}
# Select one of the options below to be the source of certificates for SPIRE Identity Exchange
tls:
externalSecret:
## @param tls.externalSecret.enabled Provide your own certificate/key via tls style Kubernetes Secret
enabled: false
## @param tls.externalSecret.secretName Specify which Secret to use
secretName: ""
certManager:
## @param tls.certManager.enabled Use certificateManager to create the certificate
enabled: false
issuer:
## @param tls.certManager.issuer.create Create an issuer to use to issue the certificate
create: true
acme:
## @param tls.certManager.issuer.acme.email Must be set in order to register with LetsEncrypt. By setting, you agree to their Terms of Service
email: ""
## @param tls.certManager.issuer.acme.server Server to use to get certificate. Defaults to LetsEncrypt
server: https://acme-v02.api.letsencrypt.org/directory
# Testing server: https://acme-staging-v02.api.letsencrypt.org/directory
## @param tls.certManager.issuer.acme.solvers [object] Configure the issuer solvers. Defaults to http01 via ingress.
solvers: {}
# - http01:
# ingress:
# ingressClassName: nginx
certificate:
## @param tls.certManager.certificate.dnsNames Override the dnsNames on the certificate request. Defaults to the same settings as Ingress
dnsNames: []
## @param tls.certManager.certificate.issuerRef.group If you are using an external plugin, specify the group for it here
## @param tls.certManager.certificate.issuerRef.kind Kind of the issuer reference. Override if you want to use a ClusterIssuer
## @param tls.certManager.certificate.issuerRef.name Name of the issuer to use. If unset, it will use the name of the built in issuer
issuerRef:
group: ""
kind: Issuer
name: ""
config: config:
## @param config.logLevel The log level, valid values are "debug", "info", "warn", and "error" ## @param config.logLevel The log level, valid values are "debug", "info", "warn", and "error"
logLevel: info logLevel: info
## @param config.logFormat The log format, valid values are "text" and "json" ## @param config.logFormat The log format, valid values are "text" and "json"
logFormat: text logFormat: text
# The metrics endpoint is always served; spire-identity-exchange requires a nonzero port for it.
telemetry:
prometheus:
## @param telemetry.prometheus.port Port for prometheus metrics
port: 4950
podMonitor:
## @param telemetry.prometheus.podMonitor.enabled Enable podMonitor for prometheus
enabled: false
## @param telemetry.prometheus.podMonitor.namespace Override where to install the podMonitor, if not set will use the same namespace as the helm release
namespace: ""
## @param telemetry.prometheus.podMonitor.labels [object] Pod labels to filter for prometheus monitoring
labels: {}
## @param imagePullSecrets [array] Image pull secret names ## @param imagePullSecrets [array] Image pull secret names
imagePullSecrets: [] imagePullSecrets: []
@@ -219,7 +171,7 @@ autoscaling:
## @param nodeSelector [object] Node selector ## @param nodeSelector [object] Node selector
nodeSelector: {} nodeSelector: {}
## @param tolerations [array] iist of tolerations ## @param tolerations [array] list of tolerations
tolerations: [] tolerations: []
## @param affinity [object] Node affinity ## @param affinity [object] Node affinity
@@ -228,158 +180,375 @@ affinity: {}
## @param trustDomain Set the trust domain to be used for the SPIFFE identifiers ## @param trustDomain Set the trust domain to be used for the SPIFFE identifiers
trustDomain: example.org trustDomain: example.org
## @param clusterName The name of this Kubernetes cluster, as it appears in SPIFFE ID paths
clusterName: example-cluster
## @param jwtIssuer The issuer URL for JWT-SVIDs. Defaults to https://oidc-discovery.$trustDomain
jwtIssuer: ""
## @param clusterDomain The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`) ## @param clusterDomain The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`)
clusterDomain: cluster.local clusterDomain: cluster.local
auth: auth:
## @param auth.plugins [object] Plugins to load plugins:
plugins: [] k8s_psat:
## @param auth.stacks [object] Stacks to load ## @param auth.plugins.k8s_psat.enabled Enable the k8s psat plugin
stacks: [] enabled: true
config:
## @param auth.plugins.k8s_psat.config.audiences [array] The audiences to allow
audiences:
- spire-identity-exchange
## @param auth.plugins.k8s_psat.config.allowedServiceAccounts [array] The service accounts that are allowed
allowedServiceAccounts:
- "*"
spiffe:
## @param auth.plugins.spiffe.enabled Enable the spiffe plugin
enabled: true
## @param auth.plugins.spiffe.keySource What source to use to fetch the keys. Can be oidc or oidcLocal. oidcLocal forces discoveryURL to be the internal discovery address.
keySource: oidcLocal
## @extra auth.plugins.spiffe.csiDriverName The CSI driver providing the SPIRE Agent workload socket this plugin attests against. Defaults to the chart level csiDriverName. Requires config.connectWithTrustBundle.
config:
## @param auth.plugins.spiffe.config.issuerURL The url to connect to for JWKS discovery
issuerURL: "${SPIFFE_JWT_ISSUER}"
## @param auth.plugins.spiffe.config.trustDomain The trust domain to use
trustDomain: "${SPIFFE_TRUST_DOMAIN}"
## @param auth.plugins.spiffe.config.pathPatterns [array] The service accounts that are allowed
pathPatterns:
- "^/k8s/${K8S_CLUSTER_NAME}/node/[^/]+"
## @param auth.plugins.spiffe.config.audiences [array] The audiences to allow
audiences:
- spire-identity-exchange
## @param auth.plugins.spiffe.config.connectWithTrustBundle Use the trust bundle to validate the issuerURL
connectWithTrustBundle: true
rest: stacks:
## @param rest.enabled Enable the rest service image_pull:
enabled: true ## @param auth.stacks.image_pull.enabled Enable the image_pull stack
## @param rest.service.type Service type enabled: true
## @param rest.service.port port for the service ## @param auth.stacks.image_pull.plugins [array] List of plugins that are required by this stack
## @param rest.service.annotations Annotations for service resource plugins:
## - spiffe
service: - k8s_psat
type: ClusterIP
port: 443 ## @param auth.unsupportedBuiltInPlugins [object] Unsupported mechanism to use plugins not yet supported by the chart.
annotations: {} unsupportedBuiltInPlugins: {}
# external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-rest.example.org
## @param rest.service.loadBalancerIP IP address to assign to load balancer (if supported) ## @param auth.passthroughPlugins Address each plugin as a stack of its own, in addition to any stacks defined
loadBalancerIP: "" passthroughPlugins: false
ingress:
## @param rest.ingress.enabled Flag to enable ingress # Listeners served with a certificate from disk. Select one of the options below to be the source of that certificate.
tls:
externalSecret:
## @param tls.externalSecret.enabled Provide your own certificate/key via tls style Kubernetes Secret
enabled: false enabled: false
## @param rest.ingress.className Ingress class name ## @param tls.externalSecret.secretName Specify which Secret to use
className: "" secretName: ""
## @param rest.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param rest.ingress.annotations [object] Annotations for ingress object
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
## @param rest.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead. certManager:
host: "spire-identity-exchange-rest" ## @param tls.certManager.enabled Use certificateManager to create the certificate
## @param rest.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param rest.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
# - host: spire-identity-exchange-rest.example.org
# paths:
# - path: /
# pathType: Prefix
## @param rest.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
# - secretName: chart-example-tls
# hosts:
# - spire-identity-exchange-rest.example.org
## Gateway API exposure for the REST endpoint. Independent of rest.ingress. The
## backend serves HTTPS, so a set tlsSecret => HTTPRoute + BackendTLSPolicy
## (reencrypt); blank tlsSecret => TLSRoute (SNI passthrough).
gatewayAPI:
## @param rest.gatewayAPI.enabled Flag to expose the REST endpoint via Gateway API
enabled: false enabled: false
## @param rest.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended. issuer:
host: "spire-identity-exchange-rest" ## @param tls.certManager.issuer.create Create an issuer to use to issue the certificate
## @param rest.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough. create: true
tlsSecret: "" acme:
## @param rest.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet) ## @param tls.certManager.issuer.acme.email Must be set in order to register with LetsEncrypt. By setting, you agree to their Terms of Service
annotations: {} email: ""
listenerSet: ## @param tls.certManager.issuer.acme.server Server to use to get certificate. Defaults to LetsEncrypt
## @param rest.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. server: https://acme-v02.api.letsencrypt.org/directory
enabled: null # Testing server: https://acme-staging-v02.api.letsencrypt.org/directory
## @param rest.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach) ## @param tls.certManager.issuer.acme.solvers [object] Configure the issuer solvers. Defaults to http01 via ingress.
parentRefs: [] solvers: {}
## @param rest.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway # - http01:
sectionName: "" # ingress:
# BackendTLSPolicy (reencrypt) is emitted automatically for the terminated # ingressClassName: nginx
# HTTPS backend when gatewayAPI.tlsSecret is set. certificate:
backendTLS: ## @param tls.certManager.certificate.dnsNames Override the dnsNames on the certificate request. Defaults to the same settings as Ingress
## @param rest.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. dnsNames: []
caCertificateRefs: [] ## @param tls.certManager.certificate.issuerRef.group If you are using an external plugin, specify the group for it here
## @param tls.certManager.certificate.issuerRef.kind Kind of the issuer reference. Override if you want to use a ClusterIssuer
## @param tls.certManager.certificate.issuerRef.name Name of the issuer to use. If unset, it will use the name of the built in issuer
issuerRef:
group: ""
kind: Issuer
name: ""
grpc: rest:
## @param grpc.enabled Enable the grpc service ## @param tls.rest.enabled Enable the REST listener served with the certificate from disk
enabled: false
## @param grpc.service.type Service type
## @param grpc.service.port port for the service
## @param grpc.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
# external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-grpc.example.org
## @param grpc.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param grpc.ingress.enabled Flag to enable ingress
enabled: false enabled: false
## @param grpc.ingress.className Ingress class name ## @param tls.rest.port Container port for the REST listener served with the certificate from disk
className: "" port: 8444
## @param grpc.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. ## @param tls.rest.service.type Service type
controllerType: "" ## @param tls.rest.service.port port for the service
## @param grpc.ingress.annotations [object] Annotations for ingress object ## @param tls.rest.service.annotations Annotations for service resource
annotations: {} ##
# kubernetes.io/ingress.class: nginx service:
# kubernetes.io/tls-acme: "true" type: ClusterIP
# nginx.ingress.kubernetes.io/ssl-redirect: "true" port: 443
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true" annotations: {}
# external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-rest.example.org
## @param tls.rest.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param tls.rest.ingress.enabled Flag to enable ingress
enabled: false
## @param tls.rest.ingress.className Ingress class name
className: ""
## @param tls.rest.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param tls.rest.ingress.annotations [object] Annotations for ingress object
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
## @param grpc.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead. ## @param tls.rest.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead.
host: "spire-identity-exchange-grpc" host: "spire-identity-exchange-rest"
## @param grpc.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var. ## @param tls.rest.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: "" tlsSecret: ""
## @param grpc.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var. ## @param tls.rest.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: [] hosts: []
# - host: spire-identity-exchange-grpc.example.org # - host: spire-identity-exchange-rest.example.org
# paths: # paths:
# - path: / # - path: /
# pathType: Prefix # pathType: Prefix
## @param grpc.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. ## @param tls.rest.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: [] tls: []
# - secretName: chart-example-tls # - secretName: chart-example-tls
# hosts: # hosts:
# - spire-identiy-exchange-grpc.example.org # - spire-identity-exchange-rest.example.org
## Gateway API exposure for the gRPC endpoint. Independent of grpc.ingress. The ## Gateway API exposure for this endpoint. A set tlsSecret gives HTTPRoute (reencrypt); blank gives TLSRoute (SNI passthrough).
## backend serves HTTPS, so a set tlsSecret => HTTPRoute + BackendTLSPolicy gatewayAPI:
## (reencrypt); blank tlsSecret => TLSRoute (SNI passthrough). ## @param tls.rest.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
gatewayAPI: enabled: false
## @param grpc.gatewayAPI.enabled Flag to expose the gRPC endpoint via Gateway API ## @param tls.rest.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-rest"
## @param tls.rest.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough.
tlsSecret: ""
## @param tls.rest.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param tls.rest.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param tls.rest.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param tls.rest.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
# BackendTLSPolicy (reencrypt) is emitted automatically for the terminated
# HTTPS backend when gatewayAPI.tlsSecret is set.
backendTLS:
## @param tls.rest.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap.
caCertificateRefs: []
grpc:
## @param tls.grpc.enabled Enable the gRPC listener served with the certificate from disk
enabled: false enabled: false
## @param grpc.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended. ## @param tls.grpc.port Container port for the gRPC listener served with the certificate from disk
host: "spire-identity-exchange-grpc" port: 8443
## @param grpc.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough. ## @param tls.grpc.service.type Service type
tlsSecret: "" ## @param tls.grpc.service.port port for the service
## @param grpc.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet) ## @param tls.grpc.service.annotations Annotations for service resource
annotations: {} ##
listenerSet: service:
## @param grpc.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. type: ClusterIP
enabled: null port: 443
## @param grpc.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach) annotations: {}
parentRefs: [] # external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-grpc.example.org
## @param grpc.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway ## @param tls.grpc.service.loadBalancerIP IP address to assign to load balancer (if supported)
sectionName: "" loadBalancerIP: ""
# BackendTLSPolicy (reencrypt) is emitted automatically for the terminated ingress:
# HTTPS backend when gatewayAPI.tlsSecret is set. ## @param tls.grpc.ingress.enabled Flag to enable ingress
backendTLS: enabled: false
## @param grpc.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. ## @param tls.grpc.ingress.className Ingress class name
caCertificateRefs: [] className: ""
## @param tls.grpc.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param tls.grpc.ingress.annotations [object] Annotations for ingress object
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
## @param tls.grpc.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead.
host: "spire-identity-exchange-grpc"
## @param tls.grpc.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param tls.grpc.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
# - host: spire-identity-exchange-grpc.example.org
# paths:
# - path: /
# pathType: Prefix
## @param tls.grpc.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
# - secretName: chart-example-tls
# hosts:
# - spire-identiy-exchange-grpc.example.org
## Gateway API exposure for this endpoint. A set tlsSecret gives HTTPRoute (reencrypt); blank gives TLSRoute (SNI passthrough).
gatewayAPI:
## @param tls.grpc.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param tls.grpc.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-grpc"
## @param tls.grpc.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough.
tlsSecret: ""
## @param tls.grpc.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param tls.grpc.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param tls.grpc.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param tls.grpc.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
# BackendTLSPolicy (reencrypt) is emitted automatically for the terminated
# HTTPS backend when gatewayAPI.tlsSecret is set.
backendTLS:
## @param tls.grpc.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap.
caCertificateRefs: []
# Listeners served with this deployment's own X509-SVID from the Workload API. No certificate files needed.
spiffe:
rest:
## @param spiffe.rest.enabled Enable the REST listener served with this deployment's own X509-SVID
enabled: true
## @param spiffe.rest.port Container port for the REST listener served with this deployment's own X509-SVID
port: 8544
## @param spiffe.rest.service.type Service type
## @param spiffe.rest.service.port port for the service
## @param spiffe.rest.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
# external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-rest-spiffe.example.org
## @param spiffe.rest.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spiffe.rest.ingress.enabled Flag to enable ingress
enabled: false
## @param spiffe.rest.ingress.className Ingress class name
className: ""
## @param spiffe.rest.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spiffe.rest.ingress.annotations [object] Annotations for ingress object
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
## @param spiffe.rest.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The rest of the rules will be autogenerated. For more customizability, use hosts[] instead.
host: "spire-identity-exchange-rest-spiffe"
## @param spiffe.rest.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spiffe.rest.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
# - host: spire-identity-exchange-rest-spiffe.example.org
# paths:
# - path: /
# pathType: Prefix
## @param spiffe.rest.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
# - secretName: chart-example-tls
# hosts:
# - spire-identity-exchange-rest-spiffe.example.org
## Gateway API exposure for this endpoint. Always a TLSRoute (SNI passthrough): an X509-SVID has no DNS SAN, so edge termination cannot validate this backend.
gatewayAPI:
## @param spiffe.rest.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spiffe.rest.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-rest-spiffe"
## @param spiffe.rest.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spiffe.rest.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spiffe.rest.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spiffe.rest.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
grpc:
## @param spiffe.grpc.enabled Enable the gRPC listener served with this deployment's own X509-SVID
enabled: false
## @param spiffe.grpc.port Container port for the gRPC listener served with this deployment's own X509-SVID
port: 8543
## @param spiffe.grpc.service.type Service type
## @param spiffe.grpc.service.port port for the service
## @param spiffe.grpc.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
# external-dns.alpha.kubernetes.io/hostname: spire-identity-exchange-grpc-spiffe.example.org
## @param spiffe.grpc.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spiffe.grpc.ingress.enabled Flag to enable ingress
enabled: false
## @param spiffe.grpc.ingress.className Ingress class name
className: ""
## @param spiffe.grpc.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spiffe.grpc.ingress.annotations [object] Annotations for ingress object
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
## @param spiffe.grpc.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. The grpc of the rules will be autogenerated. For more customizability, use hosts[] instead.
host: "spire-identity-exchange-grpc-spiffe"
## @param spiffe.grpc.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spiffe.grpc.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
# - host: spire-identity-exchange-grpc-spiffe.example.org
# paths:
# - path: /
# pathType: Prefix
## @param spiffe.grpc.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
# - secretName: chart-example-tls
# hosts:
# - spire-identiy-exchange-grpc-spiffe.example.org
## Gateway API exposure for this endpoint. Always a TLSRoute (SNI passthrough): an X509-SVID has no DNS SAN, so edge termination cannot validate this backend.
gatewayAPI:
## @param spiffe.grpc.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spiffe.grpc.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-grpc-spiffe"
## @param spiffe.grpc.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spiffe.grpc.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spiffe.grpc.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spiffe.grpc.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
tools: tools:
kubectl: kubectl:
+1 -1
View File
@@ -2,7 +2,7 @@ apiVersion: v2
name: spire-lib name: spire-lib
description: A library of helper templates for SPIRE charts. description: A library of helper templates for SPIRE charts.
type: library type: library
version: 0.3.0 version: 0.3.1
appVersion: "0.1.0" appVersion: "0.1.0"
keywords: ["spiffe", "spire", "library"] keywords: ["spiffe", "spire", "library"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-lib home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire-lib
+1 -1
View File
@@ -7,7 +7,7 @@ A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for gro
```yaml ```yaml
dependencies: dependencies:
- name: spire-lib - name: spire-lib
version: 0.3.0 version: 0.3.1
repository: https://spiffe.github.io/helm-charts-hardened/ repository: https://spiffe.github.io/helm-charts-hardened/
``` ```
@@ -10,9 +10,6 @@
{{- $labels = mergeOverwrite $labels (include "spire-lib.namespace.default_server_labels" . | fromYaml) }} {{- $labels = mergeOverwrite $labels (include "spire-lib.namespace.default_server_labels" . | fromYaml) }}
{{- if (dig "openshift" false .Values.global) }} {{- if (dig "openshift" false .Values.global) }}
{{- $_ := set $labels "security.openshift.io/scc.podSecurityLabelSync" "false" }} {{- $_ := set $labels "security.openshift.io/scc.podSecurityLabelSync" "false" }}
{{- if (index .Values "spiffe-oidc-discovery-provider").enabled }}
{{- $_ := set $labels "pod-security.kubernetes.io/enforce" "privileged" }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- $labels = mergeOverwrite $labels .Values.global.spire.namespaces.server.labels }} {{- $labels = mergeOverwrite $labels .Values.global.spire.namespaces.server.labels }}
+6 -6
View File
@@ -1,7 +1,7 @@
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: spire-server - name: spire-server
repository: file://../spire/charts/spire-server repository: file://../spire/charts/spire-server
version: 0.1.0 version: 0.1.0
@@ -43,7 +43,7 @@ dependencies:
version: 0.1.0 version: 0.1.0
- name: spire-ha-agent - name: spire-ha-agent
repository: file://../spire-ha-agent repository: file://../spire-ha-agent
version: 0.3.0 version: 0.3.1
- name: spire-server - name: spire-server
repository: file://../spire/charts/spire-server repository: file://../spire/charts/spire-server
version: 0.1.0 version: 0.1.0
@@ -58,7 +58,7 @@ dependencies:
version: 0.1.0 version: 0.1.0
- name: spire-identity-exchange - name: spire-identity-exchange
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
- name: spire-server - name: spire-server
repository: file://../spire/charts/spire-server repository: file://../spire/charts/spire-server
version: 0.1.0 version: 0.1.0
@@ -73,6 +73,6 @@ dependencies:
version: 0.1.0 version: 0.1.0
- name: spire-identity-exchange - name: spire-identity-exchange
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
digest: sha256:edf96a8d833dffffc31f0bfdd400ced75f0cf1868e2711a1cd72f51d6f099621 digest: sha256:bd10aa2236190a29056e5b32300d16883bc01635d2446a32c91ead2639b98f1d
generated: "2026-07-31T16:55:07.391766-07:00" generated: "2026-08-21T14:41:50.936953-07:00"
+6 -6
View File
@@ -4,8 +4,8 @@ description: >
A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager. A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager.
type: application type: application
version: 0.30.0 version: 0.30.1
appVersion: "1.15.2" appVersion: "1.15.3"
keywords: ["spiffe", "spire", "spire-server", "spire-agent", "oidc", "spire-controller-manager"] keywords: ["spiffe", "spire", "spire-server", "spire-agent", "oidc", "spire-controller-manager"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
sources: sources:
@@ -23,7 +23,7 @@ kubeVersion: ">=1.21.0-0"
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: spire-server - name: spire-server
alias: root-spire-server alias: root-spire-server
condition: root-spire-server.enabled condition: root-spire-server.enabled
@@ -121,7 +121,7 @@ dependencies:
- haAgentCommon - haAgentCommon
- name: spire-ha-agent - name: spire-ha-agent
repository: file://../spire-ha-agent repository: file://../spire-ha-agent
version: 0.3.0 version: 0.3.1
condition: spire-ha-agent.enabled condition: spire-ha-agent.enabled
tags: tags:
- haAgentCommon - haAgentCommon
@@ -157,7 +157,7 @@ dependencies:
alias: spire-identity-exchange-bottom-turtle-ha-a alias: spire-identity-exchange-bottom-turtle-ha-a
condition: spire-identity-exchange-bottom-turtle-ha-a.enabled condition: spire-identity-exchange-bottom-turtle-ha-a.enabled
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
tags: tags:
- bottomTurtleHAA - bottomTurtleHAA
- name: spire-server - name: spire-server
@@ -192,7 +192,7 @@ dependencies:
alias: spire-identity-exchange-bottom-turtle-ha-b alias: spire-identity-exchange-bottom-turtle-ha-b
condition: spire-identity-exchange-bottom-turtle-ha-b.enabled condition: spire-identity-exchange-bottom-turtle-ha-b.enabled
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
tags: tags:
- bottomTurtleHAB - bottomTurtleHAB
annotations: annotations:
+261 -162
View File
@@ -1,6 +1,6 @@
# spire # spire
![Version: 0.28.5](https://img.shields.io/badge/Version-0.28.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.15.2](https://img.shields.io/badge/AppVersion-1.15.2-informational?style=flat-square) ![Version: 0.30.1](https://img.shields.io/badge/Version-0.30.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.15.3](https://img.shields.io/badge/AppVersion-1.15.3-informational?style=flat-square)
[![Development Phase](https://github.com/spiffe/spiffe/blob/main/.img/maturity/dev.svg)](https://github.com/spiffe/spiffe/blob/main/MATURITY.md#development) [![Development Phase](https://github.com/spiffe/spiffe/blob/main/.img/maturity/dev.svg)](https://github.com/spiffe/spiffe/blob/main/MATURITY.md#development)
A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager. A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager.
@@ -199,43 +199,134 @@ Now you can interact with the Spire agent socket from your own application. The
### Global parameters ### Global parameters
| Name | Description | Value | | Name | Description | Value |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `global.k8s.clusterDomain` | Cluster domain name configured for Spire install | `cluster.local` | | `global.k8s.clusterDomain` | Cluster domain name configured for Spire install | `cluster.local` |
| `global.spire.clusterName` | The name of the k8s cluster for Spire install | `example-cluster` | | `global.spire.clusterName` | The name of the k8s cluster for Spire install | `example-cluster` |
| `global.spire.jwtIssuer` | The issuer for Spire JWT tokens. Defaults to oidc-discovery.$trustDomain if unset | `""` | | `global.spire.jwtIssuer` | The issuer for Spire JWT tokens. Defaults to oidc-discovery.$trustDomain if unset | `""` |
| `global.spire.trustDomain` | The trust domain for Spire install | `example.org` | | `global.spire.trustDomain` | The trust domain for Spire install | `example.org` |
| `global.spire.caSubject.country` | Country for Spire server CA | `""` | | `global.spire.caSubject.country` | Country for Spire server CA | `""` |
| `global.spire.caSubject.organization` | Organization for Spire server CA | `""` | | `global.spire.caSubject.organization` | Organization for Spire server CA | `""` |
| `global.spire.caSubject.commonName` | Common Name for Spire server CA | `""` | | `global.spire.caSubject.commonName` | Common Name for Spire server CA | `""` |
| `global.spire.recommendations.enabled` | Use recommended settings for production deployments. Default is off. | `false` | | `global.spire.recommendations.enabled` | Use recommended settings for production deployments. Default is off. | `false` |
| `global.spire.recommendations.namespaceLayout` | Set to true to use recommended values for installing across namespaces | `true` | | `global.spire.recommendations.namespaceLayout` | Set to true to use recommended values for installing across namespaces | `true` |
| `global.spire.recommendations.namespacePSS` | When chart namespace creation is enabled, label them with preffered Pod Security Standard labels | `true` | | `global.spire.recommendations.namespacePSS` | When chart namespace creation is enabled, label them with preffered Pod Security Standard labels | `true` |
| `global.spire.recommendations.priorityClassName` | Set to true to use recommended values for Pod Priority Class Names | `true` | | `global.spire.recommendations.priorityClassName` | Set to true to use recommended values for Pod Priority Class Names | `true` |
| `global.spire.recommendations.strictMode` | Check values, such as trustDomain, are overridden with a suitable value for production. | `true` | | `global.spire.recommendations.strictMode` | Check values, such as trustDomain, are overridden with a suitable value for production. | `true` |
| `global.spire.recommendations.securityContexts` | Set to true to use recommended values for Pod and Container Security Contexts | `true` | | `global.spire.recommendations.securityContexts` | Set to true to use recommended values for Pod and Container Security Contexts | `true` |
| `global.spire.recommendations.prometheus` | Enable prometheus exporters for monitoring | `true` | | `global.spire.recommendations.prometheus` | Enable prometheus exporters for monitoring | `true` |
| `global.spire.image.registry` | Override all Spire image registries at once | `""` | | `global.spire.image.registry` | Override all Spire image registries at once | `""` |
| `global.spire.namespaces.create` | Set to true to Create all namespaces. If this or either of the namespace specific create flags is set, the namespace will be created. | `false` | | `global.spire.namespaces.create` | Set to true to Create all namespaces. If this or either of the namespace specific create flags is set, the namespace will be created. | `false` |
| `global.spire.namespaces.system.name` | Name of the Spire system Namespace. | `spire-system` | | `global.spire.namespaces.system.name` | Name of the Spire system Namespace. | `spire-system` |
| `global.spire.namespaces.system.create` | Create a Namespace for Spire system resources. | `false` | | `global.spire.namespaces.system.create` | Create a Namespace for Spire system resources. | `false` |
| `global.spire.namespaces.system.annotations` | Annotations to apply to the Spire system Namespace. | `{}` | | `global.spire.namespaces.system.annotations` | Annotations to apply to the Spire system Namespace. | `{}` |
| `global.spire.namespaces.system.labels` | Labels to apply to the Spire system Namespace. | `{}` | | `global.spire.namespaces.system.labels` | Labels to apply to the Spire system Namespace. | `{}` |
| `global.spire.namespaces.server.name` | Name of the Spire server Namespace. | `spire-server` | | `global.spire.namespaces.server.name` | Name of the Spire server Namespace. | `spire-server` |
| `global.spire.namespaces.server.create` | Create a Namespace for Spire server resources. | `false` | | `global.spire.namespaces.server.create` | Create a Namespace for Spire server resources. | `false` |
| `global.spire.namespaces.server.annotations` | Annotations to apply to the Spire server Namespace. | `{}` | | `global.spire.namespaces.server.annotations` | Annotations to apply to the Spire server Namespace. | `{}` |
| `global.spire.namespaces.server.labels` | Labels to apply to the Spire server Namespace. | `{}` | | `global.spire.namespaces.server.labels` | Labels to apply to the Spire server Namespace. | `{}` |
| `global.spire.strictMode` | Check values, such as trustDomain, are overridden with a suitable value for production. | `false` | | `global.spire.strictMode` | Check values, such as trustDomain, are overridden with a suitable value for production. | `false` |
| `global.spire.ingressControllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` | | `global.spire.ingressControllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `global.spire.tools.kubectl.tag` | Set to force the tag to use for all kubectl instances | `""` | | `global.spire.gatewayAPI.manageListenerSets` | Default policy for whether services render a ListenerSet for their SNI listener. Each service may override via its gatewayAPI.listenerSet.enabled. | `true` |
| `global.installAndUpgradeHooks.enabled` | Enable Helm hooks to autofix common install/upgrade issues (should be disabled when using `helm template`) | `true` | | `global.spire.gatewayAPI.gateway.name` | Name of the shared Gateway object that routes and ListenerSets attach to | `spire` |
| `global.deleteHooks.enabled` | Enable Helm hooks to autofix common delete issues (should be disabled when using `helm template`) | `true` | | `global.spire.gatewayAPI.gateway.namespace` | Namespace of the shared Gateway object. Defaults to the release namespace if blank. | `spire-server` |
| `tags.nestedRoot` | Set the chart architecture to root nested | `false` | | `global.spire.gatewayAPI.gateway.port` | Port the shared Gateway listens on. ListenerSet listeners must match this. | `443` |
| `tags.nestedChildFull` | Set the chart mode to a child cluster with its own nested server | `false` | | `global.spire.tools.kubectl.tag` | Set to force the tag to use for all kubectl instances | `""` |
| `tags.nestedChildSecurity` | Set the chart mode to a child cluster for use with a security cluster | `false` | | `global.installAndUpgradeHooks.enabled` | Enable Helm hooks to autofix common install/upgrade issues (should be disabled when using `helm template`) | `true` |
| `tags.haAgentCommon` | Set the chart mode to deploy the common portion of a spire-ha-agent setup | `false` | | `global.deleteHooks.enabled` | Enable Helm hooks to autofix common delete issues (should be disabled when using `helm template`) | `true` |
| `tags.bottomTurtleHAA` | Setup HA side A for use with a Bottom Turtle architecture | `false` | | `tags.nestedRoot` | Set the chart architecture to root nested | `false` |
| `tags.bottomTurtleHAB` | Setup HA side B for use with a Bottom Turtle architecture | `false` | | `tags.nestedChildFull` | Set the chart mode to a child cluster with its own nested server | `false` |
| `tags.nestedChildSecurity` | Set the chart mode to a child cluster for use with a security cluster | `false` |
| `tags.haAgentCommon` | Set the chart mode to deploy the common portion of a spire-ha-agent setup | `false` |
| `tags.bottomTurtleHAA` | Setup HA side A for use with a Bottom Turtle architecture | `false` |
| `tags.bottomTurtleHAB` | Setup HA side B for use with a Bottom Turtle architecture | `false` |
| `gatewayAPI.gateway.enabled` | Render the shared Gateway object | `false` |
| `gatewayAPI.gateway.className` | gatewayClassName for the shared Gateway (e.g. "eg"). Required when enabled. | `""` |
| `gatewayAPI.gateway.annotations` | Annotations for the Gateway object | `{}` |
| `gatewayAPI.gateway.allowedListenersNamespaces` | From which namespaces ListenerSets may attach to the Gateway. One of All, Same, Selector. | `All` |
| `gatewayAPI.gateway.allowedRoutesNamespaces` | From which namespaces routes may attach directly to the base listener (used when ListenerSet management is off). One of All, Same, Selector. | `All` |
| `gatewayAPI.gateway.extraListeners` | Additional listeners to add to the Gateway | `[]` |
| `spireIdentityExchange.podSelector` | Labels selecting the exchange pods of both sides. Narrow it (for example by adding release-namespace) when other exchanges share the namespace. | `{}` |
| `spireIdentityExchange.tls.rest.enabled` | Expose the combined REST endpoint served with the on-disk certificate | `false` |
| `spireIdentityExchange.tls.rest.service.type` | Service type | `ClusterIP` |
| `spireIdentityExchange.tls.rest.service.port` | port for the service | `443` |
| `spireIdentityExchange.tls.rest.service.annotations` | Annotations for service resource | `{}` |
| `spireIdentityExchange.tls.rest.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spireIdentityExchange.tls.rest.ingress.enabled` | Flag to enable ingress | `false` |
| `spireIdentityExchange.tls.rest.ingress.className` | Ingress class name | `""` |
| `spireIdentityExchange.tls.rest.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spireIdentityExchange.tls.rest.ingress.annotations` | Annotations for ingress object | `{}` |
| `spireIdentityExchange.tls.rest.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts. | `spire-identity-exchange-rest` |
| `spireIdentityExchange.tls.rest.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spireIdentityExchange.tls.rest.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spireIdentityExchange.tls.rest.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spireIdentityExchange.tls.rest.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spireIdentityExchange.tls.rest.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-rest` |
| `spireIdentityExchange.tls.rest.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` |
| `spireIdentityExchange.tls.rest.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spireIdentityExchange.tls.rest.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spireIdentityExchange.tls.rest.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spireIdentityExchange.tls.rest.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `spireIdentityExchange.tls.rest.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` |
| `spireIdentityExchange.tls.grpc.enabled` | Expose the combined gRPC endpoint served with the on-disk certificate | `false` |
| `spireIdentityExchange.tls.grpc.service.type` | Service type | `ClusterIP` |
| `spireIdentityExchange.tls.grpc.service.port` | port for the service | `443` |
| `spireIdentityExchange.tls.grpc.service.annotations` | Annotations for service resource | `{}` |
| `spireIdentityExchange.tls.grpc.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spireIdentityExchange.tls.grpc.ingress.enabled` | Flag to enable ingress | `false` |
| `spireIdentityExchange.tls.grpc.ingress.className` | Ingress class name | `""` |
| `spireIdentityExchange.tls.grpc.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spireIdentityExchange.tls.grpc.ingress.annotations` | Annotations for ingress object | `{}` |
| `spireIdentityExchange.tls.grpc.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts. | `spire-identity-exchange-grpc` |
| `spireIdentityExchange.tls.grpc.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spireIdentityExchange.tls.grpc.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spireIdentityExchange.tls.grpc.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-grpc` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.tlsSecret` | Secret with the TLS cert for edge termination. Blank keeps passthrough. | `""` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `spireIdentityExchange.tls.grpc.gatewayAPI.backendTLS.caCertificateRefs` | ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap. | `[]` |
| `spireIdentityExchange.spiffe.rest.enabled` | Expose the combined REST endpoint served with each side's own X509-SVID | `false` |
| `spireIdentityExchange.spiffe.rest.service.type` | Service type | `ClusterIP` |
| `spireIdentityExchange.spiffe.rest.service.port` | port for the service | `443` |
| `spireIdentityExchange.spiffe.rest.service.annotations` | Annotations for service resource | `{}` |
| `spireIdentityExchange.spiffe.rest.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spireIdentityExchange.spiffe.rest.ingress.enabled` | Flag to enable ingress | `false` |
| `spireIdentityExchange.spiffe.rest.ingress.className` | Ingress class name | `""` |
| `spireIdentityExchange.spiffe.rest.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spireIdentityExchange.spiffe.rest.ingress.annotations` | Annotations for ingress object | `{}` |
| `spireIdentityExchange.spiffe.rest.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts. | `spire-identity-exchange-rest-spiffe` |
| `spireIdentityExchange.spiffe.rest.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spireIdentityExchange.spiffe.rest.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spireIdentityExchange.spiffe.rest.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-rest-spiffe` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spireIdentityExchange.spiffe.rest.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
| `spireIdentityExchange.spiffe.grpc.enabled` | Expose the combined gRPC endpoint served with each side's own X509-SVID | `false` |
| `spireIdentityExchange.spiffe.grpc.service.type` | Service type | `ClusterIP` |
| `spireIdentityExchange.spiffe.grpc.service.port` | port for the service | `443` |
| `spireIdentityExchange.spiffe.grpc.service.annotations` | Annotations for service resource | `{}` |
| `spireIdentityExchange.spiffe.grpc.service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `spireIdentityExchange.spiffe.grpc.ingress.enabled` | Flag to enable ingress | `false` |
| `spireIdentityExchange.spiffe.grpc.ingress.className` | Ingress class name | `""` |
| `spireIdentityExchange.spiffe.grpc.ingress.controllerType` | Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. | `""` |
| `spireIdentityExchange.spiffe.grpc.ingress.annotations` | Annotations for ingress object | `{}` |
| `spireIdentityExchange.spiffe.grpc.ingress.host` | Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts. | `spire-identity-exchange-grpc-spiffe` |
| `spireIdentityExchange.spiffe.grpc.ingress.tlsSecret` | Secret that has the certs. If blank will use default certs. Used with host var. | `""` |
| `spireIdentityExchange.spiffe.grpc.ingress.hosts` | Host paths for ingress object. If emtpy, rules will be built based on the host var. | `[]` |
| `spireIdentityExchange.spiffe.grpc.ingress.tls` | Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars. | `[]` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.enabled` | Flag to expose the endpoint via Gateway API | `false` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.host` | Host name for the route. If no '.' in host, trustDomain is automatically appended. | `spire-identity-exchange-grpc-spiffe` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.annotations` | Annotations for the route (and its ListenerSet) | `{}` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.listenerSet.enabled` | Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets. | `nil` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.parentRefs` | parentRefs used when ListenerSet management is disabled (direct attach) | `[]` |
| `spireIdentityExchange.spiffe.grpc.gatewayAPI.sectionName` | Listener sectionName override when attaching directly to a Gateway | `""` |
### Spire agent parameters ### Spire agent parameters
@@ -384,130 +475,138 @@ Now you can interact with the Spire agent socket from your own application. The
### Spire server parameters ### Spire server parameters
| Name | Description | Value | | Name | Description | Value |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------- | | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `internal-spire-server-bottom-turtle-ha-a.nameOverride` | Overrides the name of Spire server pods | `internal-server` | | `internal-spire-server-bottom-turtle-ha-a.nameOverride` | Overrides the name of Spire server pods | `internal-server` |
| `internal-spire-server-bottom-turtle-ha-a.caKeyType` | Key type to use for the ca | `ec-p256` | | `internal-spire-server-bottom-turtle-ha-a.caKeyType` | Key type to use for the ca | `ec-p256` |
| `internal-spire-server-bottom-turtle-ha-a.experimental.enabled` | enable experimental features | `true` | | `internal-spire-server-bottom-turtle-ha-a.experimental.enabled` | enable experimental features | `true` |
| `internal-spire-server-bottom-turtle-ha-a.experimental.agentSPIFFEIDAsSelector` | enable adding spiffe_id selectors to all agents | `true` | | `internal-spire-server-bottom-turtle-ha-a.experimental.agentSPIFFEIDAsSelector` | enable adding spiffe_id selectors to all agents | `true` |
| `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.enabled` | Enable dynamic registration | `true` | | `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.enabled` | Enable dynamic registration | `true` |
| `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.allowedIDPrefix` | The allowed ID prefix | `spire/agent/x509pop/k8s` | | `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.allowedIDPrefix` | The allowed ID prefix | `spire/agent/x509pop/k8s` |
| `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.serviceAccount` | The service account to allow in for dynamic registration | `spire-a-agent` | | `internal-spire-server-bottom-turtle-ha-a.dynamicRegistration.serviceAccount` | The service account to allow in for dynamic registration | `spire-a-agent` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.parentIDTemplate` | parent id template | `spiffe://{{ .TrustDomain }}/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.parentIDTemplate` | parent id template | `spiffe://{{ .TrustDomain }}/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.autoPopulateDNSNames` | Auto populate dns entries | `false` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.autoPopulateDNSNames` | Auto populate dns entries | `false` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.type` | The type of the entry | `oidc-discovery-provider-common` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.type` | The type of the entry | `oidc-discovery-provider-common` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled` | Enables the spire-ha-agent identity | `true` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled` | Enables the spire-ha-agent identity | `true` |
| `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.spire-identity-exchange-service.federatesWith` | List of trust domains to federate with | `[]` | | `internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-identity-exchange-service.federatesWith` | List of trust domains to federate with | `[]` |
| `internal-spire-server-bottom-turtle-ha-a.persistence.type` | What type to use for peristence | `emptyDir` | | `internal-spire-server-bottom-turtle-ha-a.persistence.type` | What type to use for peristence | `emptyDir` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `/{{ .PluginName }}/k8s${HELM_ADD_CLUSTER_NAME}/{{ .SVIDPathTrimmed }}` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `/{{ .PluginName }}/k8s${HELM_ADD_CLUSTER_NAME}/{{ .SVIDPathTrimmed }}` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.addClusterName.spiffePrefix` | Suffix the cluster name onto the spiffePrefix | `true` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.addClusterName.spiffePrefix` | Suffix the cluster name onto the spiffePrefix | `true` |
| `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.addClusterName.agentPathTemplate` | Suffix the cluster name onto the agentPathTemplate | `true` | | `internal-spire-server-bottom-turtle-ha-a.nodeAttestor.x509POP.addClusterName.agentPathTemplate` | Suffix the cluster name onto the agentPathTemplate | `true` |
| `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.enabled` | Enable upstream SPIRE server | `true` | | `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.enabled` | Enable upstream SPIRE server | `true` |
| `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.upstreamDriver` | Use an upstream driver for authentication | `upstream-a.csi.spiffe.io` | | `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.upstreamDriver` | Use an upstream driver for authentication | `upstream-a.csi.spiffe.io` |
| `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.nameOverride` | The name override setting of the root SPIRE server | `root-server` | | `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.nameOverride` | The name override setting of the root SPIRE server | `root-server` |
| `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.address` | Address for upstream Spire server | `spire-server-a` | | `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.address` | Address for upstream Spire server | `spire-server-a` |
| `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.port` | The port setting of the root SPIRE server | `8081` | | `internal-spire-server-bottom-turtle-ha-a.upstreamAuthority.spire.server.port` | The port setting of the root SPIRE server | `8081` |
| `internal-spire-server-bottom-turtle-ha-a.bundleConfigMap` | The name of the configmap to store the downstream bundle | `spire-server-a-bundle` | | `internal-spire-server-bottom-turtle-ha-a.bundleConfigMap` | The name of the configmap to store the downstream bundle | `spire-server-a-bundle` |
| `internal-spire-server-bottom-turtle-ha-a.trustSync.enabled` | Enable trust syncing | `true` | | `internal-spire-server-bottom-turtle-ha-a.trustSync.enabled` | Enable trust syncing | `true` |
| `internal-spire-server-bottom-turtle-ha-a.trustSync.domains` | the trust domains to sync | `["spire-ha"]` | | `internal-spire-server-bottom-turtle-ha-a.trustSync.domains` | the trust domains to sync | `["spire-ha"]` |
### Spire server parameters ### Spire server parameters
| Name | Description | Value | | Name | Description | Value |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------- | | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `internal-spire-server-bottom-turtle-ha-b.nameOverride` | Overrides the name of Spire server pods | `internal-server` | | `internal-spire-server-bottom-turtle-ha-b.nameOverride` | Overrides the name of Spire server pods | `internal-server` |
| `internal-spire-server-bottom-turtle-ha-b.caKeyType` | Key type to use for the ca | `ec-p256` | | `internal-spire-server-bottom-turtle-ha-b.caKeyType` | Key type to use for the ca | `ec-p256` |
| `internal-spire-server-bottom-turtle-ha-b.experimental.enabled` | enable experimental features | `true` | | `internal-spire-server-bottom-turtle-ha-b.experimental.enabled` | enable experimental features | `true` |
| `internal-spire-server-bottom-turtle-ha-b.experimental.agentSPIFFEIDAsSelector` | enable adding spiffe_id selectors to all agents | `true` | | `internal-spire-server-bottom-turtle-ha-b.experimental.agentSPIFFEIDAsSelector` | enable adding spiffe_id selectors to all agents | `true` |
| `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.enabled` | Enable dynamic registration | `true` | | `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.enabled` | Enable dynamic registration | `true` |
| `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.allowedIDPrefix` | The allowed ID prefix | `spire/agent/x509pop/k8s` | | `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.allowedIDPrefix` | The allowed ID prefix | `spire/agent/x509pop/k8s` |
| `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.serviceAccount` | The service account to allow in for dynamic registration | `spire-b-agent` | | `internal-spire-server-bottom-turtle-ha-b.dynamicRegistration.serviceAccount` | The service account to allow in for dynamic registration | `spire-b-agent` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.parentIDTemplate` | parent id template | `spiffe://{{ .TrustDomain }}/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.parentIDTemplate` | parent id template | `spiffe://{{ .TrustDomain }}/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.autoPopulateDNSNames` | Auto populate dns entries | `false` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.autoPopulateDNSNames` | Auto populate dns entries | `false` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.type` | The type of the entry | `oidc-discovery-provider-common` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.oidc-discovery-provider.type` | The type of the entry | `oidc-discovery-provider-common` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled` | Enables the spire-ha-agent identity | `true` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled` | Enables the spire-ha-agent identity | `true` |
| `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.spire-identity-exchange-service.federatesWith` | List of trust domains to federate with | `[]` | | `internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-identity-exchange-service.federatesWith` | List of trust domains to federate with | `[]` |
| `internal-spire-server-bottom-turtle-ha-b.persistence.type` | What type to use for peristence | `emptyDir` | | `internal-spire-server-bottom-turtle-ha-b.persistence.type` | What type to use for peristence | `emptyDir` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `/{{ .PluginName }}/k8s${HELM_ADD_CLUSTER_NAME}/{{ .SVIDPathTrimmed }}` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `/{{ .PluginName }}/k8s${HELM_ADD_CLUSTER_NAME}/{{ .SVIDPathTrimmed }}` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.addClusterName.spiffePrefix` | Suffix the cluster name onto the spiffePrefix | `true` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.addClusterName.spiffePrefix` | Suffix the cluster name onto the spiffePrefix | `true` |
| `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.addClusterName.agentPathTemplate` | Suffix the cluster name onto the agentPathTemplate | `true` | | `internal-spire-server-bottom-turtle-ha-b.nodeAttestor.x509POP.addClusterName.agentPathTemplate` | Suffix the cluster name onto the agentPathTemplate | `true` |
| `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.enabled` | Enable upstream SPIRE server | `true` | | `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.enabled` | Enable upstream SPIRE server | `true` |
| `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.upstreamDriver` | Use an upstream driver for authentication | `upstream-b.csi.spiffe.io` | | `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.upstreamDriver` | Use an upstream driver for authentication | `upstream-b.csi.spiffe.io` |
| `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.nameOverride` | The name override setting of the root SPIRE server | `root-server` | | `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.nameOverride` | The name override setting of the root SPIRE server | `root-server` |
| `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.address` | Address for upstream Spire server | `spire-server-b` | | `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.address` | Address for upstream Spire server | `spire-server-b` |
| `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.port` | The port setting of the root SPIRE server | `8081` | | `internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.port` | The port setting of the root SPIRE server | `8081` |
| `internal-spire-server-bottom-turtle-ha-b.bundleConfigMap` | The name of the configmap to store the downstream bundle | `spire-server-b-bundle` | | `internal-spire-server-bottom-turtle-ha-b.bundleConfigMap` | The name of the configmap to store the downstream bundle | `spire-server-b-bundle` |
| `internal-spire-server-bottom-turtle-ha-b.trustSync.enabled` | Enable trust syncing | `true` | | `internal-spire-server-bottom-turtle-ha-b.trustSync.enabled` | Enable trust syncing | `true` |
| `internal-spire-server-bottom-turtle-ha-b.trustSync.domains` | the trust domains to sync | `["spire-ha"]` | | `internal-spire-server-bottom-turtle-ha-b.trustSync.domains` | the trust domains to sync | `["spire-ha"]` |
| `downstream-spire-agent-bottom-turtle-ha-a.nameOverride` | Overrides the name of Spire agent pods | `agent-downstream` | | `downstream-spire-agent-bottom-turtle-ha-a.nameOverride` | Overrides the name of Spire agent pods | `agent-downstream` |
| `downstream-spire-agent-bottom-turtle-ha-a.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` | | `downstream-spire-agent-bottom-turtle-ha-a.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` |
| `downstream-spire-agent-bottom-turtle-ha-a.bundleConfigMap` | The name of the configmap that contains the downstream bundle | `spire-server-a-bundle` | | `downstream-spire-agent-bottom-turtle-ha-a.bundleConfigMap` | The name of the configmap that contains the downstream bundle | `spire-server-a-bundle` |
| `downstream-spire-agent-bottom-turtle-ha-a.persistence.hostPath` | Which path to use on the host when persistence.type = hostPath | `/var/lib/spire/k8s/downstream-agent-a` | | `downstream-spire-agent-bottom-turtle-ha-a.persistence.hostPath` | Which path to use on the host when persistence.type = hostPath | `/var/lib/spire/k8s/downstream-agent-a` |
| `downstream-spire-agent-bottom-turtle-ha-a.dynamicRegistration.enabled` | Enable dynamic registration | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.dynamicRegistration.enabled` | Enable dynamic registration | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.dynamicRegistration.nameOverride` | The name override to use to contact the server | `internal-server` | | `downstream-spire-agent-bottom-turtle-ha-a.dynamicRegistration.nameOverride` | The name override to use to contact the server | `internal-server` |
| `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` | | `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` |
| `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.x509POP.spiffeEndpointSocket` | Where the socket is to use for mode spiffe | `/var/run/spiffe/socat/unix/k8s-spire-agent-a/public/api.sock` | | `downstream-spire-agent-bottom-turtle-ha-a.nodeAttestor.x509POP.spiffeEndpointSocket` | Where the socket is to use for mode spiffe | `/var/run/spiffe/socat/unix/k8s-spire-agent-a/public/api.sock` |
| `downstream-spire-agent-bottom-turtle-ha-a.keyManager.memory.enabled` | Enable the memory based Key Manager | `false` | | `downstream-spire-agent-bottom-turtle-ha-a.keyManager.memory.enabled` | Enable the memory based Key Manager | `false` |
| `downstream-spire-agent-bottom-turtle-ha-a.keyManager.disk.enabled` | Enable the disk key manager | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.keyManager.disk.enabled` | Enable the disk key manager | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.keyManager.disk.mode` | Where the disk plugin will write out its data | `emptyDir` | | `downstream-spire-agent-bottom-turtle-ha-a.keyManager.disk.mode` | Where the disk plugin will write out its data | `emptyDir` |
| `downstream-spire-agent-bottom-turtle-ha-a.healthChecks.port` | Health check port | `9981` | | `downstream-spire-agent-bottom-turtle-ha-a.healthChecks.port` | Health check port | `9981` |
| `downstream-spire-agent-bottom-turtle-ha-a.telemetry.prometheus.port` | Prometheus port to use | `9989` | | `downstream-spire-agent-bottom-turtle-ha-a.telemetry.prometheus.port` | Prometheus port to use | `9989` |
| `downstream-spire-agent-bottom-turtle-ha-a.socketPath` | Socket path to use | `/var/run/spire/agent/sockets/a/csi.spiffe.io/public/spire-agent.sock` | | `downstream-spire-agent-bottom-turtle-ha-a.socketPath` | Socket path to use | `/var/run/spire/agent/sockets/a/csi.spiffe.io/public/spire-agent.sock` |
| `downstream-spire-agent-bottom-turtle-ha-a.sockets.hostBasePath` | Path on the host to place sockets | `/var/run/spire/agent/sockets/a` | | `downstream-spire-agent-bottom-turtle-ha-a.sockets.hostBasePath` | Path on the host to place sockets | `/var/run/spire/agent/sockets/a` |
| `downstream-spire-agent-bottom-turtle-ha-a.sockets.admin.enabled` | Enable admin socket | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.sockets.admin.enabled` | Enable admin socket | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.sockets.admin.mountOnHost` | Mount admin socket on host | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.sockets.admin.mountOnHost` | Mount admin socket on host | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.authorizedDelegates` | List of workloads able to use the delegation api | `["/spire-ha-agent"]` | | `downstream-spire-agent-bottom-turtle-ha-a.authorizedDelegates` | List of workloads able to use the delegation api | `["/spire-ha-agent"]` |
| `downstream-spire-agent-bottom-turtle-ha-a.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` |
| `downstream-spire-agent-bottom-turtle-ha-a.workloadAttestors.k8s.brokerAPI.accessPolicy` | The default accessPolicy | `permissive` | | `downstream-spire-agent-bottom-turtle-ha-a.workloadAttestors.k8s.brokerAPI.accessPolicy` | The default accessPolicy | `permissive` |
| `downstream-spire-agent-bottom-turtle-ha-a.workloadAttestors.k8s.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` | | `downstream-spire-agent-bottom-turtle-ha-a.workloadAttestors.k8s.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.nameOverride` | Overrides the name of Spire agent pods | `agent-downstream` | | `downstream-spire-agent-bottom-turtle-ha-b.nameOverride` | Overrides the name of Spire agent pods | `agent-downstream` |
| `downstream-spire-agent-bottom-turtle-ha-b.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` | | `downstream-spire-agent-bottom-turtle-ha-b.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` |
| `downstream-spire-agent-bottom-turtle-ha-b.bundleConfigMap` | The name of the configmap that contains the downstream bundle | `spire-server-b-bundle` | | `downstream-spire-agent-bottom-turtle-ha-b.bundleConfigMap` | The name of the configmap that contains the downstream bundle | `spire-server-b-bundle` |
| `downstream-spire-agent-bottom-turtle-ha-b.persistence.hostPath` | Which path to use on the host when persistence.type = hostPath | `/var/lib/spire/k8s/downstream-agent-b` | | `downstream-spire-agent-bottom-turtle-ha-b.persistence.hostPath` | Which path to use on the host when persistence.type = hostPath | `/var/lib/spire/k8s/downstream-agent-b` |
| `downstream-spire-agent-bottom-turtle-ha-b.dynamicRegistration.enabled` | Enable dynamic registration | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.dynamicRegistration.enabled` | Enable dynamic registration | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.dynamicRegistration.nameOverride` | The name override to use to contact the server | `internal-server` | | `downstream-spire-agent-bottom-turtle-ha-b.dynamicRegistration.nameOverride` | The name override to use to contact the server | `internal-server` |
| `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` | | `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.k8sPSAT.enabled` | Enable the k8s projected access token node attestor | `false` |
| `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.x509POP.enabled` | Enable the x509 pop node attestor | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.x509POP.spiffeEndpointSocket` | Where the socket is to use for mode spiffe | `/var/run/spiffe/socat/unix/k8s-spire-agent-b/public/api.sock` | | `downstream-spire-agent-bottom-turtle-ha-b.nodeAttestor.x509POP.spiffeEndpointSocket` | Where the socket is to use for mode spiffe | `/var/run/spiffe/socat/unix/k8s-spire-agent-b/public/api.sock` |
| `downstream-spire-agent-bottom-turtle-ha-b.keyManager.memory.enabled` | Enable the memory based Key Manager | `false` | | `downstream-spire-agent-bottom-turtle-ha-b.keyManager.memory.enabled` | Enable the memory based Key Manager | `false` |
| `downstream-spire-agent-bottom-turtle-ha-b.keyManager.disk.enabled` | Enable the disk key manager | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.keyManager.disk.enabled` | Enable the disk key manager | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.keyManager.disk.mode` | Where the disk plugin will write out its data | `emptyDir` | | `downstream-spire-agent-bottom-turtle-ha-b.keyManager.disk.mode` | Where the disk plugin will write out its data | `emptyDir` |
| `downstream-spire-agent-bottom-turtle-ha-b.healthChecks.port` | Health check port | `9982` | | `downstream-spire-agent-bottom-turtle-ha-b.healthChecks.port` | Health check port | `9982` |
| `downstream-spire-agent-bottom-turtle-ha-b.telemetry.prometheus.port` | Prometheus port to use | `9990` | | `downstream-spire-agent-bottom-turtle-ha-b.telemetry.prometheus.port` | Prometheus port to use | `9990` |
| `downstream-spire-agent-bottom-turtle-ha-b.socketPath` | Socket path to use | `/var/run/spire/agent/sockets/b/csi.spiffe.io/public/spire-agent.sock` | | `downstream-spire-agent-bottom-turtle-ha-b.socketPath` | Socket path to use | `/var/run/spire/agent/sockets/b/csi.spiffe.io/public/spire-agent.sock` |
| `downstream-spire-agent-bottom-turtle-ha-b.sockets.hostBasePath` | Path on the host to place sockets | `/var/run/spire/agent/sockets/b` | | `downstream-spire-agent-bottom-turtle-ha-b.sockets.hostBasePath` | Path on the host to place sockets | `/var/run/spire/agent/sockets/b` |
| `downstream-spire-agent-bottom-turtle-ha-b.sockets.admin.enabled` | Enable admin socket | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.sockets.admin.enabled` | Enable admin socket | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.sockets.admin.mountOnHost` | Mount admin socket on host | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.sockets.admin.mountOnHost` | Mount admin socket on host | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.authorizedDelegates` | List of workloads able to use the delegation api | `["/spire-ha-agent"]` | | `downstream-spire-agent-bottom-turtle-ha-b.authorizedDelegates` | List of workloads able to use the delegation api | `["/spire-ha-agent"]` |
| `downstream-spire-agent-bottom-turtle-ha-b.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` |
| `downstream-spire-agent-bottom-turtle-ha-b.workloadAttestors.k8s.brokerAPI.accessPolicy` | The default accessPolicy | `permissive` | | `downstream-spire-agent-bottom-turtle-ha-b.workloadAttestors.k8s.brokerAPI.accessPolicy` | The default accessPolicy | `permissive` |
| `downstream-spire-agent-bottom-turtle-ha-b.workloadAttestors.k8s.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` | | `downstream-spire-agent-bottom-turtle-ha-b.workloadAttestors.k8s.brokerAPI.brokers.spire-ha-agent.enabled` | Enable the spire-ha-agent by default | `true` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-a.fullnameOverride` | Fullname override | `spiffe-csi-driver-downstream-a` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-a.fullnameOverride` | Fullname override | `spiffe-csi-driver-downstream-a` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-a.agentSocketPath` | path to agent socket | `/var/run/spire/agent/sockets/a/csi.spiffe.io/public/spire-agent.sock` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-a.agentSocketPath` | path to agent socket | `/var/run/spire/agent/sockets/a/csi.spiffe.io/public/spire-agent.sock` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-a.pluginName` | The name of the plugin instance | `a.csi.spiffe.io` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-a.pluginName` | The name of the plugin instance | `a.csi.spiffe.io` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-a.healthChecks.port` | The health check port | `9814` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-a.healthChecks.port` | The health check port | `9814` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-b.fullnameOverride` | Fullname override | `spiffe-csi-driver-downstream-b` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-b.fullnameOverride` | Fullname override | `spiffe-csi-driver-downstream-b` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-b.agentSocketPath` | path to agent socket | `/var/run/spire/agent/sockets/b/csi.spiffe.io/public/spire-agent.sock` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-b.agentSocketPath` | path to agent socket | `/var/run/spire/agent/sockets/b/csi.spiffe.io/public/spire-agent.sock` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-b.pluginName` | The name of the plugin instance | `b.csi.spiffe.io` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-b.pluginName` | The name of the plugin instance | `b.csi.spiffe.io` |
| `downstream-spiffe-csi-driver-bottom-turtle-ha-b.healthChecks.port` | The health check port | `9816` | | `downstream-spiffe-csi-driver-bottom-turtle-ha-b.healthChecks.port` | The health check port | `9816` |
| `spire-identity-exchange-bottom-turtle-ha-a.enabled` | Enable the spire-identity-exchange | `false` | | `spire-identity-exchange-bottom-turtle-ha-a.enabled` | Enable the spire-identity-exchange | `false` |
| `spire-identity-exchange-bottom-turtle-ha-a.nameOverride` | name override | `identity-exchange` | | `spire-identity-exchange-bottom-turtle-ha-a.nameOverride` | name override | `identity-exchange` |
| `spire-identity-exchange-bottom-turtle-ha-a.csiDriverName` | CSI driver name to use | `a.csi.spiffe.io` | | `spire-identity-exchange-bottom-turtle-ha-a.csiDriverName` | CSI driver name to use | `a.csi.spiffe.io` |
| `spire-identity-exchange-bottom-turtle-ha-a.rest.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-a-rest` | | `spire-identity-exchange-bottom-turtle-ha-a.tls.rest.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-a-rest` |
| `spire-identity-exchange-bottom-turtle-ha-a.grpc.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-a-grpc` | | `spire-identity-exchange-bottom-turtle-ha-a.tls.grpc.ingress.host` | Hostname override for the grpc ingress service | `spire-identity-exchange-a-grpc` |
| `spire-identity-exchange-bottom-turtle-ha-a.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` | | `spire-identity-exchange-bottom-turtle-ha-a.spiffe.rest.ingress.host` | Hostname override for the SVID-served rest ingress service | `spire-identity-exchange-a-rest-spiffe` |
| `spire-identity-exchange-bottom-turtle-ha-b.enabled` | Enable the spire-identity-exchange | `false` | | `spire-identity-exchange-bottom-turtle-ha-a.spiffe.grpc.ingress.host` | Hostname override for the SVID-served grpc ingress service | `spire-identity-exchange-a-grpc-spiffe` |
| `spire-identity-exchange-bottom-turtle-ha-b.nameOverride` | name override | `identity-exchange` | | `spire-identity-exchange-bottom-turtle-ha-a.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` |
| `spire-identity-exchange-bottom-turtle-ha-b.csiDriverName` | CSI driver name to use | `b.csi.spiffe.io` | | `spire-identity-exchange-bottom-turtle-ha-a.auth.plugins.spiffe.csiDriverName` | The csi driver the spiffe plugin reads its trust bundle from. The shared ha-agent, since that is what mints the oidc discovery provider's serving svid. | `csi.spiffe.io` |
| `spire-identity-exchange-bottom-turtle-ha-b.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` | | `spire-identity-exchange-bottom-turtle-ha-a.auth.plugins.spiffe.config.discoveryURL` | The OIDC discovery provider to fetch keys from. This chart gives it a fullnameOverride, so the keySource convention does not apply. | `https://spiffe-oidc-discovery-provider` |
| `spire-identity-exchange-bottom-turtle-ha-b.rest.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-b-rest` | | `spire-identity-exchange-bottom-turtle-ha-b.enabled` | Enable the spire-identity-exchange | `false` |
| `spire-identity-exchange-bottom-turtle-ha-b.grpc.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-b-grpc` | | `spire-identity-exchange-bottom-turtle-ha-b.nameOverride` | name override | `identity-exchange` |
| `spire-identity-exchange-bottom-turtle-ha-b.csiDriverName` | CSI driver name to use | `b.csi.spiffe.io` |
| `spire-identity-exchange-bottom-turtle-ha-b.server.nameOverride` | The name override setting of the internal SPIRE server | `internal-server` |
| `spire-identity-exchange-bottom-turtle-ha-b.tls.rest.ingress.host` | Hostname override for the rest ingress service | `spire-identity-exchange-b-rest` |
| `spire-identity-exchange-bottom-turtle-ha-b.tls.grpc.ingress.host` | Hostname override for the grpc ingress service | `spire-identity-exchange-b-grpc` |
| `spire-identity-exchange-bottom-turtle-ha-b.spiffe.rest.ingress.host` | Hostname override for the SVID-served rest ingress service | `spire-identity-exchange-b-rest-spiffe` |
| `spire-identity-exchange-bottom-turtle-ha-b.spiffe.grpc.ingress.host` | Hostname override for the SVID-served grpc ingress service | `spire-identity-exchange-b-grpc-spiffe` |
| `spire-identity-exchange-bottom-turtle-ha-b.auth.plugins.spiffe.csiDriverName` | The csi driver the spiffe plugin reads its trust bundle from. The shared ha-agent, since that is what mints the oidc discovery provider's serving svid. | `csi.spiffe.io` |
| `spire-identity-exchange-bottom-turtle-ha-b.auth.plugins.spiffe.config.discoveryURL` | The OIDC discovery provider to fetch keys from. This chart gives it a fullnameOverride, so the keySource convention does not apply. | `https://spiffe-oidc-discovery-provider` |
@@ -0,0 +1,64 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "spire-nested.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "spire-nested.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{- define "spire-nested.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "spire-nested.labels" -}}
helm.sh/chart: {{ include "spire-nested.chart" . }}
app.kubernetes.io/name: {{ include "spire-nested.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
The namespace the SPIRE server side components land in. Resolved the same way as
spire-identity-exchange.namespace, so the combined exposure lands beside the exchange
pods it selects — a Service selector is namespace scoped.
*/}}
{{- define "spire-nested.server-namespace" -}}
{{- if and (dig "spire" "recommendations" "enabled" false .Values.global) (dig "spire" "recommendations" "namespaceLayout" true .Values.global) }}
{{- if ne (len (dig "spire" "namespaces" "server" "name" "" .Values.global)) 0 }}
{{- .Values.global.spire.namespaces.server.name }}
{{- else }}
{{- printf "spire-server" }}
{{- end }}
{{- else -}}
{{- .Release.Namespace -}}
{{- end -}}
{{- end -}}
{{/*
Base name for the combined identity exchange objects. Keyed on the release name so it
reads like the per-side exchanges, which the sides' own releases name spire-a-identity-
exchange / spire-b-identity-exchange — so these never collide with them either.
*/}}
{{- define "spire-nested.identity-exchange-name" -}}
{{- printf "%s-identity-exchange" .Release.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
@@ -0,0 +1,3 @@
{{- if .Values.gatewayAPI.gateway.enabled }}
{{- include "spire-lib.gateway-resource" (dict "root" . "gatewayObject" .Values.gatewayAPI.gateway) }}
{{- end }}
@@ -0,0 +1,15 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.grpc.enabled .Values.spireIdentityExchange.spiffe.grpc.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-grpc-spiffe" (include "spire-nested.identity-exchange-name" .) -}}
{{/* Passthrough only. These backends serve an X509-SVID, whose only SAN is a
spiffe:// URI, so a BackendTLSPolicy hostname check could never match. */}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spireIdentityExchange.spiffe.grpc.gatewayAPI
"name" $fullName
"namespace" (include "spire-nested.server-namespace" .)
"svcName" $fullName
"port" .Values.spireIdentityExchange.spiffe.grpc.service.port
"labels" (include "spire-nested.labels" .)
"routeKind" "TLSRoute"
"backendTLS" false) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.grpc.enabled .Values.spireIdentityExchange.spiffe.grpc.ingress.enabled -}}
{{- $port := .Values.spireIdentityExchange.spiffe.grpc.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spireIdentityExchange.spiffe.grpc.ingress) }}
{{- $fullName := printf "%s-grpc-spiffe" (include "spire-nested.identity-exchange-name" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spireIdentityExchange.spiffe.grpc.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spireIdentityExchange.spiffe.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spireIdentityExchange.spiffe.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{ include "spire-nested.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spireIdentityExchange.spiffe.grpc.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,25 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.grpc.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-nested.identity-exchange-name" . }}-grpc-spiffe
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{- include "spire-nested.labels" . | nindent 4 }}
{{- with .Values.spireIdentityExchange.spiffe.grpc.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spireIdentityExchange.spiffe.grpc.service.type }}
{{- if and (eq .Values.spireIdentityExchange.spiffe.grpc.service.type "LoadBalancer") .Values.spireIdentityExchange.spiffe.grpc.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spireIdentityExchange.spiffe.grpc.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spireIdentityExchange.spiffe.grpc.service.port }}
targetPort: grpc-spiffe
protocol: TCP
selector:
{{- toYaml .Values.spireIdentityExchange.podSelector | nindent 4 }}
{{- end }}
@@ -0,0 +1,15 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.rest.enabled .Values.spireIdentityExchange.spiffe.rest.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-rest-spiffe" (include "spire-nested.identity-exchange-name" .) -}}
{{/* Passthrough only. These backends serve an X509-SVID, whose only SAN is a
spiffe:// URI, so a BackendTLSPolicy hostname check could never match. */}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spireIdentityExchange.spiffe.rest.gatewayAPI
"name" $fullName
"namespace" (include "spire-nested.server-namespace" .)
"svcName" $fullName
"port" .Values.spireIdentityExchange.spiffe.rest.service.port
"labels" (include "spire-nested.labels" .)
"routeKind" "TLSRoute"
"backendTLS" false) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.rest.enabled .Values.spireIdentityExchange.spiffe.rest.ingress.enabled -}}
{{- $port := .Values.spireIdentityExchange.spiffe.rest.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spireIdentityExchange.spiffe.rest.ingress) }}
{{- $fullName := printf "%s-rest-spiffe" (include "spire-nested.identity-exchange-name" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spireIdentityExchange.spiffe.rest.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spireIdentityExchange.spiffe.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spireIdentityExchange.spiffe.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{ include "spire-nested.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spireIdentityExchange.spiffe.rest.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,25 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.spiffe.rest.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-nested.identity-exchange-name" . }}-rest-spiffe
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{- include "spire-nested.labels" . | nindent 4 }}
{{- with .Values.spireIdentityExchange.spiffe.rest.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spireIdentityExchange.spiffe.rest.service.type }}
{{- if and (eq .Values.spireIdentityExchange.spiffe.rest.service.type "LoadBalancer") .Values.spireIdentityExchange.spiffe.rest.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spireIdentityExchange.spiffe.rest.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spireIdentityExchange.spiffe.rest.service.port }}
targetPort: rest-spiffe
protocol: TCP
selector:
{{- toYaml .Values.spireIdentityExchange.podSelector | nindent 4 }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.grpc.enabled .Values.spireIdentityExchange.tls.grpc.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-grpc" (include "spire-nested.identity-exchange-name" .) -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.spireIdentityExchange.tls.grpc.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spireIdentityExchange.tls.grpc.gatewayAPI
"name" $fullName
"namespace" (include "spire-nested.server-namespace" .)
"svcName" $fullName
"port" .Values.spireIdentityExchange.tls.grpc.service.port
"labels" (include "spire-nested.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.grpc.enabled .Values.spireIdentityExchange.tls.grpc.ingress.enabled -}}
{{- $port := .Values.spireIdentityExchange.tls.grpc.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spireIdentityExchange.tls.grpc.ingress) }}
{{- $fullName := printf "%s-grpc" (include "spire-nested.identity-exchange-name" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spireIdentityExchange.tls.grpc.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spireIdentityExchange.tls.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spireIdentityExchange.tls.grpc.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{ include "spire-nested.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spireIdentityExchange.tls.grpc.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,25 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.grpc.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-nested.identity-exchange-name" . }}-grpc
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{- include "spire-nested.labels" . | nindent 4 }}
{{- with .Values.spireIdentityExchange.tls.grpc.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spireIdentityExchange.tls.grpc.service.type }}
{{- if and (eq .Values.spireIdentityExchange.tls.grpc.service.type "LoadBalancer") .Values.spireIdentityExchange.tls.grpc.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spireIdentityExchange.tls.grpc.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spireIdentityExchange.tls.grpc.service.port }}
targetPort: grpc
protocol: TCP
selector:
{{- toYaml .Values.spireIdentityExchange.podSelector | nindent 4 }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.rest.enabled .Values.spireIdentityExchange.tls.rest.gatewayAPI.enabled -}}
{{- $fullName := printf "%s-rest" (include "spire-nested.identity-exchange-name" .) -}}
{{- $routeKind := include "spire-lib.gateway-route-kind" (dict "gatewayAPI" .Values.spireIdentityExchange.tls.rest.gatewayAPI) -}}
{{- include "spire-lib.gateway-routes" (dict
"root" .
"gatewayAPI" .Values.spireIdentityExchange.tls.rest.gatewayAPI
"name" $fullName
"namespace" (include "spire-nested.server-namespace" .)
"svcName" $fullName
"port" .Values.spireIdentityExchange.tls.rest.service.port
"labels" (include "spire-nested.labels" .)
"routeKind" $routeKind
"backendTLS" (eq $routeKind "HTTPRoute")) }}
{{- end }}
@@ -0,0 +1,39 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.rest.enabled .Values.spireIdentityExchange.tls.rest.ingress.enabled -}}
{{- $port := .Values.spireIdentityExchange.tls.rest.service.port }}
{{- $ingressControllerType := include "spire-lib.ingress-controller-type" (dict "global" .Values.global "ingress" .Values.spireIdentityExchange.tls.rest.ingress) }}
{{- $fullName := printf "%s-rest" (include "spire-nested.identity-exchange-name" .) }}
{{- $path := "/" }}
{{- $pathType := "Prefix" }}
{{- $tlsSection := true }}
{{- $annotations := deepCopy .Values.spireIdentityExchange.tls.rest.ingress.annotations }}
{{- if eq $ingressControllerType "ingress-nginx" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/force-ssl-redirect" "true" }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/backend-protocol" "HTTPS" }}
{{- if not .Values.spireIdentityExchange.tls.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "nginx.ingress.kubernetes.io/ssl-passthrough" "true" }}
{{- end }}
{{- else if eq $ingressControllerType "openshift" }}
{{- if .Values.spireIdentityExchange.tls.rest.ingress.tlsSecret }}
{{- $_ := set $annotations "route.openshift.io/termination" "reencrypt" }}
{{- else }}
{{- $_ := set $annotations "route.openshift.io/termination" "passthrough" }}
{{- end }}
{{- $path = "" }}
{{- $pathType = "ImplementationSpecific" }}
{{- $tlsSection = false }}
{{- end }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{ include "spire-nested.labels" . | nindent 4 }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{ include "spire-lib.ingress-spec" (dict "ingress" .Values.spireIdentityExchange.tls.rest.ingress "svcName" $fullName "port" $port "path" $path "pathType" $pathType "tlsSection" $tlsSection "Values" .Values) | nindent 2 }}
{{- end }}
@@ -0,0 +1,25 @@
{{- if and .Values.tags.haAgentCommon .Values.spireIdentityExchange.tls.rest.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "spire-nested.identity-exchange-name" . }}-rest
namespace: {{ include "spire-nested.server-namespace" . }}
labels:
{{- include "spire-nested.labels" . | nindent 4 }}
{{- with .Values.spireIdentityExchange.tls.rest.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.spireIdentityExchange.tls.rest.service.type }}
{{- if and (eq .Values.spireIdentityExchange.tls.rest.service.type "LoadBalancer") .Values.spireIdentityExchange.tls.rest.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.spireIdentityExchange.tls.rest.service.loadBalancerIP }}
{{- end }}
ports:
- name: https
port: {{ .Values.spireIdentityExchange.tls.rest.service.port }}
targetPort: rest
protocol: TCP
selector:
{{- toYaml .Values.spireIdentityExchange.podSelector | nindent 4 }}
{{- end }}
+305 -24
View File
@@ -73,6 +73,24 @@ global:
## @param global.spire.ingressControllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""]. ## @param global.spire.ingressControllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
ingressControllerType: "" ingressControllerType: ""
## Shared Gateway that routes and ListenerSets attach to. The Gateway object itself is
## rendered by the `gatewayAPI.gateway` block of this chart. Gateway API support is
## independent of ingress and can be enabled alongside it.
gatewayAPI:
## @param global.spire.gatewayAPI.manageListenerSets Default policy for whether services render a ListenerSet for their SNI listener. Each service may override via its gatewayAPI.listenerSet.enabled.
manageListenerSets: true
gateway:
## @param global.spire.gatewayAPI.gateway.name Name of the shared Gateway object that routes and ListenerSets attach to
name: spire
## The Gateway object and every route's parentRef both read this value, so they
## cannot disagree. It defaults to the server namespace so the Gateway sits with
## the workloads it fronts; a ListenerSet in another namespace still attaches, as
## the Gateway allows listeners from all namespaces by default.
## @param global.spire.gatewayAPI.gateway.namespace Namespace of the shared Gateway object. Defaults to the release namespace if blank.
namespace: spire-server
## @param global.spire.gatewayAPI.gateway.port Port the shared Gateway listens on. ListenerSet listeners must match this.
port: 443
tools: tools:
kubectl: kubectl:
## @param global.spire.tools.kubectl.tag Set to force the tag to use for all kubectl instances ## @param global.spire.tools.kubectl.tag Set to force the tag to use for all kubectl instances
@@ -108,6 +126,233 @@ tags:
## @param tags.bottomTurtleHAB Setup HA side B for use with a Bottom Turtle architecture ## @param tags.bottomTurtleHAB Setup HA side B for use with a Bottom Turtle architecture
bottomTurtleHAB: false bottomTurtleHAB: false
## The shared Gateway that routes and ListenerSets attach to. Only one release in a cluster
## should render it. name/namespace/port come from global.spire.gatewayAPI.gateway; the
## class and listener policy are local.
##
gatewayAPI:
gateway:
## @param gatewayAPI.gateway.enabled Render the shared Gateway object
enabled: false
## @param gatewayAPI.gateway.className gatewayClassName for the shared Gateway (e.g. "eg"). Required when enabled.
className: ""
## @param gatewayAPI.gateway.annotations [object] Annotations for the Gateway object
annotations: {}
## @param gatewayAPI.gateway.allowedListenersNamespaces From which namespaces ListenerSets may attach to the Gateway. One of All, Same, Selector.
allowedListenersNamespaces: All
## @param gatewayAPI.gateway.allowedRoutesNamespaces From which namespaces routes may attach directly to the base listener (used when ListenerSet management is off). One of All, Same, Selector.
allowedRoutesNamespaces: All
## @param gatewayAPI.gateway.extraListeners [array] Additional listeners to add to the Gateway
extraListeners: []
## Combined exposure fronting the spire-identity-exchange of both HA sides. Only rendered
## with tags.haAgentCommon; the per-side exposures under bottomTurtleHAA/B are untouched.
## Each endpoint gets one Service selecting both sides' exchange pods, so the Ingress and
## the Gateway API route need only a single backend. The matching listener must be enabled
## on the sides themselves; if it is not, the Service simply has no endpoints.
spireIdentityExchange:
## @param spireIdentityExchange.podSelector [object] Labels selecting the exchange pods of both sides. Narrow it (for example by adding release-namespace) when other exchanges share the namespace.
podSelector:
component: spire-identity-exchange
## Endpoints served with the certificate each side loads from disk.
tls:
rest:
## @param spireIdentityExchange.tls.rest.enabled Expose the combined REST endpoint served with the on-disk certificate
enabled: false
## @param spireIdentityExchange.tls.rest.service.type Service type
## @param spireIdentityExchange.tls.rest.service.port port for the service
## @param spireIdentityExchange.tls.rest.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
## @param spireIdentityExchange.tls.rest.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spireIdentityExchange.tls.rest.ingress.enabled Flag to enable ingress
enabled: false
## @param spireIdentityExchange.tls.rest.ingress.className Ingress class name
className: ""
## @param spireIdentityExchange.tls.rest.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spireIdentityExchange.tls.rest.ingress.annotations [object] Annotations for ingress object
annotations: {}
## @param spireIdentityExchange.tls.rest.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts.
host: "spire-identity-exchange-rest"
## @param spireIdentityExchange.tls.rest.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spireIdentityExchange.tls.rest.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
## @param spireIdentityExchange.tls.rest.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
## Gateway API exposure for this endpoint. A set tlsSecret gives HTTPRoute (reencrypt); blank gives TLSRoute (SNI passthrough).
gatewayAPI:
## @param spireIdentityExchange.tls.rest.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spireIdentityExchange.tls.rest.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-rest"
## @param spireIdentityExchange.tls.rest.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough.
tlsSecret: ""
## @param spireIdentityExchange.tls.rest.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spireIdentityExchange.tls.rest.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spireIdentityExchange.tls.rest.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spireIdentityExchange.tls.rest.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
backendTLS:
## @param spireIdentityExchange.tls.rest.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap.
caCertificateRefs: []
grpc:
## @param spireIdentityExchange.tls.grpc.enabled Expose the combined gRPC endpoint served with the on-disk certificate
enabled: false
## @param spireIdentityExchange.tls.grpc.service.type Service type
## @param spireIdentityExchange.tls.grpc.service.port port for the service
## @param spireIdentityExchange.tls.grpc.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
## @param spireIdentityExchange.tls.grpc.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spireIdentityExchange.tls.grpc.ingress.enabled Flag to enable ingress
enabled: false
## @param spireIdentityExchange.tls.grpc.ingress.className Ingress class name
className: ""
## @param spireIdentityExchange.tls.grpc.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spireIdentityExchange.tls.grpc.ingress.annotations [object] Annotations for ingress object
annotations: {}
## @param spireIdentityExchange.tls.grpc.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts.
host: "spire-identity-exchange-grpc"
## @param spireIdentityExchange.tls.grpc.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spireIdentityExchange.tls.grpc.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
## @param spireIdentityExchange.tls.grpc.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
## Gateway API exposure for this endpoint. A set tlsSecret gives HTTPRoute (reencrypt); blank gives TLSRoute (SNI passthrough).
gatewayAPI:
## @param spireIdentityExchange.tls.grpc.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spireIdentityExchange.tls.grpc.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-grpc"
## @param spireIdentityExchange.tls.grpc.gatewayAPI.tlsSecret Secret with the TLS cert for edge termination. Blank keeps passthrough.
tlsSecret: ""
## @param spireIdentityExchange.tls.grpc.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spireIdentityExchange.tls.grpc.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spireIdentityExchange.tls.grpc.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spireIdentityExchange.tls.grpc.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
backendTLS:
## @param spireIdentityExchange.tls.grpc.gatewayAPI.backendTLS.caCertificateRefs [array] ConfigMap refs holding the backend CA used to validate the re-encrypted connection. Defaults to the SPIRE bundle configmap.
caCertificateRefs: []
## Endpoints served with each side's own X509-SVID. Gateway API is always a TLSRoute
## (SNI passthrough) here: an X509-SVID has no DNS SAN, so edge termination could never
## validate these backends.
spiffe:
rest:
## @param spireIdentityExchange.spiffe.rest.enabled Expose the combined REST endpoint served with each side's own X509-SVID
enabled: false
## @param spireIdentityExchange.spiffe.rest.service.type Service type
## @param spireIdentityExchange.spiffe.rest.service.port port for the service
## @param spireIdentityExchange.spiffe.rest.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
## @param spireIdentityExchange.spiffe.rest.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spireIdentityExchange.spiffe.rest.ingress.enabled Flag to enable ingress
enabled: false
## @param spireIdentityExchange.spiffe.rest.ingress.className Ingress class name
className: ""
## @param spireIdentityExchange.spiffe.rest.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spireIdentityExchange.spiffe.rest.ingress.annotations [object] Annotations for ingress object
annotations: {}
## @param spireIdentityExchange.spiffe.rest.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts.
host: "spire-identity-exchange-rest-spiffe"
## @param spireIdentityExchange.spiffe.rest.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spireIdentityExchange.spiffe.rest.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
## @param spireIdentityExchange.spiffe.rest.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
## Gateway API exposure for this endpoint. Always a TLSRoute (SNI passthrough).
gatewayAPI:
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-rest-spiffe"
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spireIdentityExchange.spiffe.rest.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
grpc:
## @param spireIdentityExchange.spiffe.grpc.enabled Expose the combined gRPC endpoint served with each side's own X509-SVID
enabled: false
## @param spireIdentityExchange.spiffe.grpc.service.type Service type
## @param spireIdentityExchange.spiffe.grpc.service.port port for the service
## @param spireIdentityExchange.spiffe.grpc.service.annotations Annotations for service resource
##
service:
type: ClusterIP
port: 443
annotations: {}
## @param spireIdentityExchange.spiffe.grpc.service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: ""
ingress:
## @param spireIdentityExchange.spiffe.grpc.ingress.enabled Flag to enable ingress
enabled: false
## @param spireIdentityExchange.spiffe.grpc.ingress.className Ingress class name
className: ""
## @param spireIdentityExchange.spiffe.grpc.ingress.controllerType Specify what type of ingress controller you're using to add the necessary annotations accordingly. If blank, autodetection is attempted. If other, no annotations will be added. Must be one of [ingress-nginx, openshift, other, ""].
controllerType: ""
## @param spireIdentityExchange.spiffe.grpc.ingress.annotations [object] Annotations for ingress object
annotations: {}
## @param spireIdentityExchange.spiffe.grpc.ingress.host Host name for the ingress. If no '.' in host, trustDomain is automatically appended. Must differ from the per-side hosts.
host: "spire-identity-exchange-grpc-spiffe"
## @param spireIdentityExchange.spiffe.grpc.ingress.tlsSecret Secret that has the certs. If blank will use default certs. Used with host var.
tlsSecret: ""
## @param spireIdentityExchange.spiffe.grpc.ingress.hosts [array] Host paths for ingress object. If emtpy, rules will be built based on the host var.
hosts: []
## @param spireIdentityExchange.spiffe.grpc.ingress.tls [array] Secrets containining TLS certs to enable https on ingress. If emtpy, rules will be built based on the host and tlsSecret vars.
tls: []
## Gateway API exposure for this endpoint. Always a TLSRoute (SNI passthrough).
gatewayAPI:
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.enabled Flag to expose the endpoint via Gateway API
enabled: false
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.host Host name for the route. If no '.' in host, trustDomain is automatically appended.
host: "spire-identity-exchange-grpc-spiffe"
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.annotations [object] Annotations for the route (and its ListenerSet)
annotations: {}
listenerSet:
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.listenerSet.enabled Manage a ListenerSet for this service's SNI listener. Null inherits global.spire.gatewayAPI.manageListenerSets.
enabled: null
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.parentRefs [array] parentRefs used when ListenerSet management is disabled (direct attach)
parentRefs: []
## @param spireIdentityExchange.spiffe.grpc.gatewayAPI.sectionName Listener sectionName override when attaching directly to a Gateway
sectionName: ""
## subcharts ## subcharts
## @section Spire agent parameters ## @section Spire agent parameters
@@ -497,10 +742,10 @@ internal-spire-server-bottom-turtle-ha-a:
spire-ha-agent: spire-ha-agent:
## @param internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled Enables the spire-ha-agent identity ## @param internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled Enables the spire-ha-agent identity
enabled: true enabled: true
spire-identity-exchange-service: spire-identity-exchange-service:
## @param internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.spire-identity-exchange-service.federatesWith [array] List of trust domains to federate with ## @param internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-identity-exchange-service.federatesWith [array] List of trust domains to federate with
federatesWith: federatesWith:
- spire-ha - spire-ha
persistence: persistence:
## @param internal-spire-server-bottom-turtle-ha-a.persistence.type What type to use for peristence ## @param internal-spire-server-bottom-turtle-ha-a.persistence.type What type to use for peristence
type: emptyDir type: emptyDir
@@ -579,10 +824,10 @@ internal-spire-server-bottom-turtle-ha-b:
spire-ha-agent: spire-ha-agent:
## @param internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled Enables the spire-ha-agent identity ## @param internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.enabled Enables the spire-ha-agent identity
enabled: true enabled: true
spire-identity-exchange-service: spire-identity-exchange-service:
## @param internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.spire-identity-exchange-service.federatesWith [array] List of trust domains to federate with ## @param internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-identity-exchange-service.federatesWith [array] List of trust domains to federate with
federatesWith: federatesWith:
- spire-ha - spire-ha
persistence: persistence:
## @param internal-spire-server-bottom-turtle-ha-b.persistence.type What type to use for peristence ## @param internal-spire-server-bottom-turtle-ha-b.persistence.type What type to use for peristence
type: emptyDir type: emptyDir
@@ -799,17 +1044,35 @@ spire-identity-exchange-bottom-turtle-ha-a:
nameOverride: identity-exchange nameOverride: identity-exchange
## @param spire-identity-exchange-bottom-turtle-ha-a.csiDriverName CSI driver name to use ## @param spire-identity-exchange-bottom-turtle-ha-a.csiDriverName CSI driver name to use
csiDriverName: a.csi.spiffe.io csiDriverName: a.csi.spiffe.io
rest: tls:
ingress: rest:
## @param spire-identity-exchange-bottom-turtle-ha-a.rest.ingress.host Hostname override for the rest ingress service ingress:
host: "spire-identity-exchange-a-rest" ## @param spire-identity-exchange-bottom-turtle-ha-a.tls.rest.ingress.host Hostname override for the rest ingress service
grpc: host: "spire-identity-exchange-a-rest"
ingress: grpc:
## @param spire-identity-exchange-bottom-turtle-ha-a.grpc.ingress.host Hostname override for the rest ingress service ingress:
host: "spire-identity-exchange-a-grpc" ## @param spire-identity-exchange-bottom-turtle-ha-a.tls.grpc.ingress.host Hostname override for the grpc ingress service
host: "spire-identity-exchange-a-grpc"
spiffe:
rest:
ingress:
## @param spire-identity-exchange-bottom-turtle-ha-a.spiffe.rest.ingress.host Hostname override for the SVID-served rest ingress service
host: "spire-identity-exchange-a-rest-spiffe"
grpc:
ingress:
## @param spire-identity-exchange-bottom-turtle-ha-a.spiffe.grpc.ingress.host Hostname override for the SVID-served grpc ingress service
host: "spire-identity-exchange-a-grpc-spiffe"
server: server:
## @param spire-identity-exchange-bottom-turtle-ha-a.server.nameOverride The name override setting of the internal SPIRE server ## @param spire-identity-exchange-bottom-turtle-ha-a.server.nameOverride The name override setting of the internal SPIRE server
nameOverride: internal-server nameOverride: internal-server
auth:
plugins:
spiffe:
## @param spire-identity-exchange-bottom-turtle-ha-a.auth.plugins.spiffe.csiDriverName The csi driver the spiffe plugin reads its trust bundle from. The shared ha-agent, since that is what mints the oidc discovery provider's serving svid.
csiDriverName: csi.spiffe.io
config:
## @param spire-identity-exchange-bottom-turtle-ha-a.auth.plugins.spiffe.config.discoveryURL The OIDC discovery provider to fetch keys from. This chart gives it a fullnameOverride, so the keySource convention does not apply.
discoveryURL: https://spiffe-oidc-discovery-provider
spire-identity-exchange-bottom-turtle-ha-b: spire-identity-exchange-bottom-turtle-ha-b:
## @param spire-identity-exchange-bottom-turtle-ha-b.enabled Enable the spire-identity-exchange ## @param spire-identity-exchange-bottom-turtle-ha-b.enabled Enable the spire-identity-exchange
@@ -821,11 +1084,29 @@ spire-identity-exchange-bottom-turtle-ha-b:
server: server:
## @param spire-identity-exchange-bottom-turtle-ha-b.server.nameOverride The name override setting of the internal SPIRE server ## @param spire-identity-exchange-bottom-turtle-ha-b.server.nameOverride The name override setting of the internal SPIRE server
nameOverride: internal-server nameOverride: internal-server
rest: tls:
ingress: rest:
## @param spire-identity-exchange-bottom-turtle-ha-b.rest.ingress.host Hostname override for the rest ingress service ingress:
host: "spire-identity-exchange-b-rest" ## @param spire-identity-exchange-bottom-turtle-ha-b.tls.rest.ingress.host Hostname override for the rest ingress service
grpc: host: "spire-identity-exchange-b-rest"
ingress: grpc:
## @param spire-identity-exchange-bottom-turtle-ha-b.grpc.ingress.host Hostname override for the rest ingress service ingress:
host: "spire-identity-exchange-b-grpc" ## @param spire-identity-exchange-bottom-turtle-ha-b.tls.grpc.ingress.host Hostname override for the grpc ingress service
host: "spire-identity-exchange-b-grpc"
spiffe:
rest:
ingress:
## @param spire-identity-exchange-bottom-turtle-ha-b.spiffe.rest.ingress.host Hostname override for the SVID-served rest ingress service
host: "spire-identity-exchange-b-rest-spiffe"
grpc:
ingress:
## @param spire-identity-exchange-bottom-turtle-ha-b.spiffe.grpc.ingress.host Hostname override for the SVID-served grpc ingress service
host: "spire-identity-exchange-b-grpc-spiffe"
auth:
plugins:
spiffe:
## @param spire-identity-exchange-bottom-turtle-ha-b.auth.plugins.spiffe.csiDriverName The csi driver the spiffe plugin reads its trust bundle from. The shared ha-agent, since that is what mints the oidc discovery provider's serving svid.
csiDriverName: csi.spiffe.io
config:
## @param spire-identity-exchange-bottom-turtle-ha-b.auth.plugins.spiffe.config.discoveryURL The OIDC discovery provider to fetch keys from. This chart gives it a fullnameOverride, so the keySource convention does not apply.
discoveryURL: https://spiffe-oidc-discovery-provider
+4 -4
View File
@@ -1,7 +1,7 @@
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: spire-server - name: spire-server
repository: file://./charts/spire-server repository: file://./charts/spire-server
version: 0.1.0 version: 0.1.0
@@ -34,6 +34,6 @@ dependencies:
version: 0.1.0 version: 0.1.0
- name: spire-identity-exchange - name: spire-identity-exchange
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
digest: sha256:5bd67eff208fb2918e03b52ab9ac5b2802558106d72a4e4ac94034a1b387c613 digest: sha256:2916c04b61f4813e2e107b84a2168fdf141c67086658e1adbb9501b8425cd6e1
generated: "2026-07-31T16:55:07.012434-07:00" generated: "2026-08-21T14:41:50.353186-07:00"
+4 -4
View File
@@ -4,8 +4,8 @@ description: >
A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager. A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager.
type: application type: application
version: 0.30.0 version: 0.30.1
appVersion: "1.14.5" appVersion: "1.15.3"
keywords: ["spiffe", "spire", "spire-server", "spire-agent", "oidc", "spire-controller-manager"] keywords: ["spiffe", "spire", "spire-server", "spire-agent", "oidc", "spire-controller-manager"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
sources: sources:
@@ -25,7 +25,7 @@ kubeVersion: ">=1.21.0-0"
dependencies: dependencies:
- name: spire-lib - name: spire-lib
repository: file://../spire-lib repository: file://../spire-lib
version: 0.3.0 version: 0.3.1
- name: spire-server - name: spire-server
condition: spire-server.enabled condition: spire-server.enabled
repository: file://./charts/spire-server repository: file://./charts/spire-server
@@ -71,7 +71,7 @@ dependencies:
- name: spire-identity-exchange - name: spire-identity-exchange
condition: spire-identity-exchange.enabled condition: spire-identity-exchange.enabled
repository: file://../spire-identity-exchange repository: file://../spire-identity-exchange
version: 0.2.0 version: 0.2.1
annotations: annotations:
org.opencontainers.image.source: https://github.com/spiffe/helm-charts-hardened org.opencontainers.image.source: https://github.com/spiffe/helm-charts-hardened
artifacthub.io/category: security artifacthub.io/category: security
+1 -1
View File
@@ -1,6 +1,6 @@
# spire # spire
![Version: 0.28.5](https://img.shields.io/badge/Version-0.28.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.15.2](https://img.shields.io/badge/AppVersion-1.15.2-informational?style=flat-square) ![Version: 0.30.1](https://img.shields.io/badge/Version-0.30.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.15.3](https://img.shields.io/badge/AppVersion-1.15.3-informational?style=flat-square)
[![Development Phase](https://github.com/spiffe/spiffe/blob/main/.img/maturity/dev.svg)](https://github.com/spiffe/spiffe/blob/main/MATURITY.md#development) [![Development Phase](https://github.com/spiffe/spiffe/blob/main/.img/maturity/dev.svg)](https://github.com/spiffe/spiffe/blob/main/MATURITY.md#development)
A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager. A Helm chart for deploying the complete Spire stack including: spire-server, spire-agent, spiffe-csi-driver, spiffe-oidc-discovery-provider and spire-controller-manager.
+52 -50
View File
@@ -25,54 +25,56 @@ A Helm chart to install the SPIFFE CSI driver.
### SPIFFE CSI Driver Chart parameters ### SPIFFE CSI Driver Chart parameters
| Name | Description | Value | | Name | Description | Value |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `pluginName` | Set the csi driver name deployed to Kubernetes. | `csi.spiffe.io` | | `pluginName` | Set the csi driver name deployed to Kubernetes. | `csi.spiffe.io` |
| `image.registry` | The OCI registry to pull the image from | `ghcr.io` | | `image.registry` | The OCI registry to pull the image from | `ghcr.io` |
| `image.repository` | The repository within the registry | `spiffe/spiffe-csi-driver` | | `image.repository` | The repository within the registry | `spiffe/spiffe-csi-driver` |
| `image.pullPolicy` | The image pull policy | `IfNotPresent` | | `image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` |
| `resources` | Resource requests and limits for spiffe-csi-driver and its initContainers | `{}` | | `resources` | Resource requests and limits for spiffe-csi-driver and its initContainers | `{}` |
| `extraEnvVars` | Extra environment variables to be added to the spiffe-csi-driver container | `[]` | | `extraEnvVars` | Extra environment variables to be added to the spiffe-csi-driver container | `[]` |
| `healthChecks.port` | The healthcheck port for spiffe-csi-driver | `9809` | | `healthChecks.port` | The healthcheck port for spiffe-csi-driver | `9809` |
| `updateStrategy.type` | The update strategy to use to replace existing DaemonSet pods with new pods. Can be RollingUpdate or OnDelete. | `RollingUpdate` | | `updateStrategy.type` | The update strategy to use to replace existing DaemonSet pods with new pods. Can be RollingUpdate or OnDelete. | `RollingUpdate` |
| `updateStrategy.rollingUpdate.maxUnavailable` | Max unavailable pods during update. Can be a number or a percentage. | `1` | | `updateStrategy.rollingUpdate.maxUnavailable` | Max unavailable pods during update. Can be a number or a percentage. | `1` |
| `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` | | `livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `5` |
| `livenessProbe.timeoutSeconds` | Timeout value in seconds for livenessProbe | `5` | | `livenessProbe.timeoutSeconds` | Timeout value in seconds for livenessProbe | `5` |
| `imagePullSecrets` | Image pull secret details for spiffe-csi-driver | `[]` | | `imagePullSecrets` | Image pull secret details for spiffe-csi-driver | `[]` |
| `nameOverride` | Name override for spiffe-csi-driver | `""` | | `nameOverride` | Name override for spiffe-csi-driver | `""` |
| `namespaceOverride` | Namespace to install spiffe-csi-driver | `""` | | `namespaceOverride` | Namespace to install spiffe-csi-driver | `""` |
| `serverNamespaceOverride` | Override the namespace that the spire-server is installed into | `""` | | `serverNamespaceOverride` | Override the namespace that the spire-server is installed into | `""` |
| `validatingAdmissionPolicy.enabled` | When set to auto, the validatingAdmissionPolicy will be enabled when the pluginName == "upstream.csi.spiffe.io" and k8s >= 1.30.0. Valid options are [auto, true, false] | `auto` | | `validatingAdmissionPolicy.enabled` | When set to auto, the validatingAdmissionPolicy will be enabled when the pluginName == "upstream.csi.spiffe.io" and k8s >= 1.30.0. Valid options are [auto, true, false] | `auto` |
| `fullnameOverride` | Full name override for spiffe-csi-driver | `""` | | `fullnameOverride` | Full name override for spiffe-csi-driver | `""` |
| `csiDriverLabels` | Labels to apply to the CSIDriver | `{}` | | `csiDriverLabels` | Labels to apply to the CSIDriver | `{}` |
| `initContainers` | Init Containers to apply to the CSI Driver DaemonSet | `[]` | | `csiDriverAnnotations` | Annotations to apply to the CSIDriver | `{}` |
| `serviceAccount.create` | Specifies whether a service account should be created | `true` | | `syncWave` | The argocd.argoproj.io/sync-wave value applied to the CSIDriver on OpenShift, ensuring the CSI driver reconciles before workloads that depend on its csi-ephemeral-volume-profile label | `-1` |
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` | | `initContainers` | Init Containers to apply to the CSI Driver DaemonSet | `[]` |
| `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated. | `""` | | `serviceAccount.create` | Specifies whether a service account should be created | `true` |
| `podAnnotations` | Pod annotations for spiffe-csi-driver | `{}` | | `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
| `podLabels` | Labels to add to pods | `{}` | | `serviceAccount.name` | The name of the service account to use. If not set and create is true, a name is generated. | `""` |
| `podSecurityContext` | Security context for CSI driver pods | `{}` | | `podAnnotations` | Pod annotations for spiffe-csi-driver | `{}` |
| `securityContext` | Security context for CSI driver containers | `{}` | | `podLabels` | Labels to add to pods | `{}` |
| `hostNetwork` | Enable hostNetwork for the DaemonSet | `false` | | `podSecurityContext` | Security context for CSI driver pods | `{}` |
| `nodeSelector` | Node selector for CSI driver pods | `{}` | | `securityContext` | Security context for CSI driver containers | `{}` |
| `tolerations` | Tolerations for CSI driver pods | `[]` | | `hostNetwork` | Enable hostNetwork for the DaemonSet | `false` |
| `affinity` | Node affinity | `{}` | | `nodeSelector` | Node selector for CSI driver pods | `{}` |
| `nodeDriverRegistrar.image.registry` | The OCI registry to pull the image from | `registry.k8s.io` | | `tolerations` | Tolerations for CSI driver pods | `[]` |
| `nodeDriverRegistrar.image.repository` | The repository within the registry | `sig-storage/csi-node-driver-registrar` | | `affinity` | Node affinity | `{}` |
| `nodeDriverRegistrar.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `nodeDriverRegistrar.image.registry` | The OCI registry to pull the image from | `registry.k8s.io` |
| `nodeDriverRegistrar.image.tag` | Overrides the image tag | `v2.15.0` | | `nodeDriverRegistrar.image.repository` | The repository within the registry | `sig-storage/csi-node-driver-registrar` |
| `nodeDriverRegistrar.extraEnvVars` | Extra environment variables to be added to the nodeDriverRegistrar container | `[]` | | `nodeDriverRegistrar.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `agentSocketPath` | The unix socket path to the spire-agent | `/run/spire/agent-sockets/spire-agent.sock` | | `nodeDriverRegistrar.image.tag` | Overrides the image tag | `v2.15.0` |
| `kubeletPath` | Path to kubelet file | `/var/lib/kubelet` | | `nodeDriverRegistrar.extraEnvVars` | Extra environment variables to be added to the nodeDriverRegistrar container | `[]` |
| `priorityClassName` | Priority class assigned to daemonset pods. Can be auto set with global.recommendations.priorityClassName. | `""` | | `agentSocketPath` | The unix socket path to the spire-agent | `/run/spire/agent-sockets/spire-agent.sock` |
| `restrictedScc.enabled` | Enables the creation of a SecurityContextConstraint based on the restricted SCC with CSI volume support | `false` | | `kubeletPath` | Path to kubelet file | `/var/lib/kubelet` |
| `restrictedScc.name` | Set the name of the restricted SCC with CSI support | `""` | | `priorityClassName` | Priority class assigned to daemonset pods. Can be auto set with global.recommendations.priorityClassName. | `""` |
| `restrictedScc.version` | Version of the restricted SCC | `2` | | `restrictedScc.enabled` | Enables the creation of a SecurityContextConstraint based on the restricted SCC with CSI volume support | `false` |
| `selinux.enabled` | Enable selinux support | `false` | | `restrictedScc.name` | Set the name of the restricted SCC with CSI support | `""` |
| `selinux.context` | Which selinux context to use | `container_file_t` | | `restrictedScc.version` | Version of the restricted SCC | `2` |
| `selinux.image.registry` | The OCI registry to pull the image from | `registry.access.redhat.com` | | `selinux.enabled` | Enable selinux support | `false` |
| `selinux.image.repository` | The repository within the registry | `ubi10/ubi-minimal` | | `selinux.context` | Which selinux context to use | `container_file_t` |
| `selinux.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `selinux.image.registry` | The OCI registry to pull the image from | `registry.access.redhat.com` |
| `selinux.image.tag` | Overrides the image tag whose default is the chart appVersion | `10.1-1776834797` | | `selinux.image.repository` | The repository within the registry | `ubi10/ubi-minimal` |
| `selinux.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `selinux.image.tag` | Overrides the image tag whose default is the chart appVersion | `10.1-1776834797` |
@@ -3,10 +3,19 @@
{{- $_ := set $labels "security.openshift.io/csi-ephemeral-volume-profile" "restricted" }} {{- $_ := set $labels "security.openshift.io/csi-ephemeral-volume-profile" "restricted" }}
{{- end }} {{- end }}
{{- $labels = mergeOverwrite $labels .Values.csiDriverLabels }} {{- $labels = mergeOverwrite $labels .Values.csiDriverLabels }}
{{- $annotations := dict }}
{{- if (dig "openshift" false .Values.global) }}
{{- $_ := set $annotations "argocd.argoproj.io/sync-wave" (toString .Values.syncWave) }}
{{- end }}
{{- $annotations = mergeOverwrite $annotations .Values.csiDriverAnnotations }}
apiVersion: storage.k8s.io/v1 apiVersion: storage.k8s.io/v1
kind: CSIDriver kind: CSIDriver
metadata: metadata:
name: {{ .Values.pluginName | quote }} name: {{ .Values.pluginName | quote }}
{{- with $annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with $labels }} {{- with $labels }}
labels: labels:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
@@ -76,6 +76,12 @@ fullnameOverride: ""
## @param csiDriverLabels Labels to apply to the CSIDriver ## @param csiDriverLabels Labels to apply to the CSIDriver
csiDriverLabels: {} csiDriverLabels: {}
## @param csiDriverAnnotations Annotations to apply to the CSIDriver
csiDriverAnnotations: {}
## @param syncWave The argocd.argoproj.io/sync-wave value applied to the CSIDriver on OpenShift, ensuring the CSI driver reconciles before workloads that depend on its csi-ephemeral-volume-profile label
syncWave: -1
## @param initContainers Init Containers to apply to the CSI Driver DaemonSet ## @param initContainers Init Containers to apply to the CSI Driver DaemonSet
initContainers: [] initContainers: []
@@ -3,7 +3,7 @@ name: spiffe-oidc-discovery-provider
description: A Helm chart to install the SPIFFE OIDC discovery provider. description: A Helm chart to install the SPIFFE OIDC discovery provider.
type: application type: application
version: 0.1.0 version: 0.1.0
appVersion: "1.15.2" appVersion: "1.15.3"
keywords: ["spiffe", "oidc"] keywords: ["spiffe", "oidc"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
sources: sources:
@@ -102,6 +102,7 @@ A Helm chart to install the SPIFFE OIDC discovery provider.
| `nodeSelector` | Node selector | `{}` | | `nodeSelector` | Node selector | `{}` |
| `tolerations` | iist of tolerations | `[]` | | `tolerations` | iist of tolerations | `[]` |
| `affinity` | Node affinity | `{}` | | `affinity` | Node affinity | `{}` |
| `topologySpreadConstraints` | Topology spread constraints for resilience | `[]` |
| `trustDomain` | Set the trust domain to be used for the SPIFFE identifiers | `example.org` | | `trustDomain` | Set the trust domain to be used for the SPIFFE identifiers | `example.org` |
| `clusterDomain` | The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`) | `cluster.local` | | `clusterDomain` | The name of the Kubernetes cluster (`kubeadm init --service-dns-domain`) | `cluster.local` |
| `telemetry.prometheus.enabled` | Flag to enable prometheus monitoring | `false` | | `telemetry.prometheus.enabled` | Flag to enable prometheus monitoring | `false` |
@@ -220,3 +220,7 @@ spec:
tolerations: tolerations:
{{- toYaml . | nindent 8 }} {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -1,42 +0,0 @@
{{- if eq (.Values.global.openshift | toString) "true" }}
apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
name: {{ include "spiffe-oidc-discovery-provider.fullname" . }}
readOnlyRootFilesystem: true
runAsUser:
type: RunAsAny
seLinuxContext:
type: RunAsAny
supplementalGroups:
type: RunAsAny
users:
- system:serviceaccount:{{ include "spiffe-oidc-discovery-provider.namespace" . }}:{{ include "spiffe-oidc-discovery-provider.serviceAccountName" . }}
- system:serviceaccount:{{ include "spiffe-oidc-discovery-provider.namespace" . }}:{{ include "spiffe-oidc-discovery-provider.serviceAccountName" . }}-pre-delete
volumes:
- configMap
- csi
- downwardAPI
- emptyDir
- ephemeral
- hostPath
- projected
- secret
allowedCapabilities: null
allowHostDirVolumePlugin: true
allowHostIPC: true
allowHostNetwork: true
allowHostPID: true
allowHostPorts: true
allowPrivilegeEscalation: true
allowPrivilegedContainer: true
defaultAddCapabilities: null
fsGroup:
type: RunAsAny
groups: []
priority: null
requiredDropCapabilities: null
seccompProfiles:
- '*'
{{ end }}
@@ -267,6 +267,9 @@ tolerations: []
## @param affinity [object] Node affinity ## @param affinity [object] Node affinity
affinity: {} affinity: {}
## @param topologySpreadConstraints [array] Topology spread constraints for resilience
topologySpreadConstraints: []
## @param trustDomain Set the trust domain to be used for the SPIFFE identifiers ## @param trustDomain Set the trust domain to be used for the SPIFFE identifiers
trustDomain: example.org trustDomain: example.org
+1 -1
View File
@@ -3,7 +3,7 @@ name: spire-agent
description: A Helm chart to install the SPIRE agent. description: A Helm chart to install the SPIRE agent.
type: application type: application
version: 0.1.0 version: 0.1.0
appVersion: "1.15.2" appVersion: "1.15.3"
keywords: ["spiffe", "spire-agent"] keywords: ["spiffe", "spire-agent"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
sources: sources:
@@ -473,7 +473,7 @@ spec:
volumes: volumes:
- name: spire-config - name: spire-config
configMap: configMap:
name: {{ include "spire-agent.fullname" . }} name: {{ printf "%s%s" (include "spire-agent.fullname" .) $nameSuffix | quote }}
{{- if .Values.keyManager.disk.enabled }} {{- if .Values.keyManager.disk.enabled }}
- name: spire-key-manager - name: spire-key-manager
{{- if eq .Values.keyManager.disk.mode "hostPath" }} {{- if eq .Values.keyManager.disk.mode "hostPath" }}
+1 -1
View File
@@ -3,7 +3,7 @@ name: spire-server
description: A Helm chart to install the SPIRE server. description: A Helm chart to install the SPIRE server.
type: application type: application
version: 0.1.0 version: 0.1.0
appVersion: "1.15.2" appVersion: "1.15.3"
keywords: ["spiffe", "spire-server", "spire-controller-manager"] keywords: ["spiffe", "spire-server", "spire-controller-manager"]
home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire
sources: sources:
+32 -6
View File
@@ -87,7 +87,11 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `image.pullPolicy` | The image pull policy | `IfNotPresent` | | `image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `image.tag` | Overrides the image tag whose default is the chart appVersion | `""` |
| `kind` | Define SPIRE server deployment type. Can be statefulset/deployment. Defaults to statefulset if not set. This feature is experimental. | `statefulset` | | `kind` | Define SPIRE server deployment type. Can be statefulset/deployment. Defaults to statefulset if not set. This feature is experimental. | `statefulset` |
| `updateStrategy` | Rollout strategy for the server, mapped to spec.updateStrategy when kind is "statefulset" and to spec.strategy when kind is "deployment". Left empty the Kubernetes default applies, which for a Deployment surges a second server before the old one goes away. Set `{type: Recreate}` to keep at most one server running, as a memory keyManager or an in-memory datastore requires. | `{}` |
| `externalServer` | Deploy only the bundle ConfigMap, RBAC rules, and identity documents but not the server. Use in a nested setup where the server is external. | `false` | | `externalServer` | Deploy only the bundle ConfigMap, RBAC rules, and identity documents but not the server. Use in a nested setup where the server is external. | `false` |
| `externalServerSubject.kind` | RBAC subject kind the external (nested) server's downstream bindings are granted to. One of "User" (client-certificate identity, the historical default), "Group", or "ServiceAccount" (e.g. for a static-token kubeconfig). Only used when externalServer is true. | `User` |
| `externalServerSubject.name` | Name of the subject. For kind "User" it must match the CN of the client certificate the external server presents; for kind "Group" it is the group name (e.g. a certificate O value); for kind "ServiceAccount" it is the name of the (operator-managed, out-of-band) ServiceAccount. | `spire-root` |
| `externalServerSubject.namespace` | Namespace of the ServiceAccount. Only used when kind is "ServiceAccount"; empty uses the server namespace. | `""` |
| `imagePullSecrets` | Pull secrets for images | `[]` | | `imagePullSecrets` | Pull secrets for images | `[]` |
| `nameOverride` | Name override | `""` | | `nameOverride` | Name override | `""` |
| `crNameOverride` | Name override for any custom resources | `""` | | `crNameOverride` | Name override for any custom resources | `""` |
@@ -105,6 +109,7 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `service.port` | Port for the created service | `443` | | `service.port` | Port for the created service | `443` |
| `service.annotations` | Annotations to add to the service object | `{}` | | `service.annotations` | Annotations to add to the service object | `{}` |
| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | | `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` |
| `service.externalTrafficPolicy` | Traffic policy applied when service.type is LoadBalancer (e.g. "Local" to preserve client source IP). Defaults to "Cluster" when left empty. | `""` |
| `configMap.annotations` | Annotations to add to the SPIRE Server ConfigMap | `{}` | | `configMap.annotations` | Annotations to add to the SPIRE Server ConfigMap | `{}` |
| `resources` | Resource requests and limits | `{}` | | `resources` | Resource requests and limits | `{}` |
| `autoscaling.enabled` | Flag to enable autoscaling | `false` | | `autoscaling.enabled` | Flag to enable autoscaling | `false` |
@@ -112,6 +117,9 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `autoscaling.maxReplicas` | Maximum replicas for autoscaling | `100` | | `autoscaling.maxReplicas` | Maximum replicas for autoscaling | `100` |
| `autoscaling.scaleOnSPIREServerOnly` | Flag to only consider the main SPIRE container for autoscaling purposes | `false` | | `autoscaling.scaleOnSPIREServerOnly` | Flag to only consider the main SPIRE container for autoscaling purposes | `false` |
| `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization that triggers autoscaling | `80` | | `autoscaling.targetCPUUtilizationPercentage` | Target CPU utilization that triggers autoscaling | `80` |
| `podDisruptionBudget.enabled` | Flag to enable a PodDisruptionBudget for the SPIRE server pods | `false` |
| `podDisruptionBudget.minAvailable` | Minimum number/percentage of pods that must remain available (mutually exclusive with maxUnavailable) | `""` |
| `podDisruptionBudget.maxUnavailable` | Maximum number/percentage of pods that can be unavailable (mutually exclusive with minAvailable) | `""` |
| `nodeSelector` | Select specific nodes to run on (currently only amd64 is supported by Tornjak) | `{}` | | `nodeSelector` | Select specific nodes to run on (currently only amd64 is supported by Tornjak) | `{}` |
| `tolerations` | List of tolerations | `[]` | | `tolerations` | List of tolerations | `[]` |
| `affinity` | List of node affinities | `{}` | | `affinity` | List of node affinities | `{}` |
@@ -133,12 +141,13 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `dataStore.sql.host` | Only used when type != "sqlite3" | `""` | | `dataStore.sql.host` | Only used when type != "sqlite3" | `""` |
| `dataStore.sql.port` | If 0 (default), it will auto set to 5432 for postgres and 3306 for mysql. Only used by those databases. | `0` | | `dataStore.sql.port` | If 0 (default), it will auto set to 5432 for postgres and 3306 for mysql. Only used by those databases. | `0` |
| `dataStore.sql.username` | Only used when type != "sqlite3" | `spire` | | `dataStore.sql.username` | Only used when type != "sqlite3" | `spire` |
| `dataStore.sql.password` | Only used when type != "sqlite3" | `""` | | `dataStore.sql.password` | Only used when type != "sqlite3". For postgres/aws_postgres, leave empty to omit the password from the connection string (e.g. TLS client-certificate or IAM authentication). | `""` |
| `dataStore.sql.file` | Data source file. Only used when type == "sqlite3" | `/run/spire/data/datastore.sqlite3` | | `dataStore.sql.file` | Data source file. Only used when type == "sqlite3" and inMemory is false | `/run/spire/data/datastore.sqlite3` |
| `dataStore.sql.inMemory` | Hold the sqlite3 datastore in memory instead of in a file, in which case `file` is unused. The datastore starts empty on every restart, so this only suits a single replica whose registration entries are recreated at startup, for example by the controller manager writing static entries. Required to run as a deployment on sqlite3, since a deployment has no durable per-pod storage. | `false` |
| `dataStore.sql.options` | takes an array of objects of form {<key>: <value>} to use when building the database connection string | `[]` | | `dataStore.sql.options` | takes an array of objects of form {<key>: <value>} to use when building the database connection string | `[]` |
| `dataStore.sql.rootCAPath` | Path to Root CA bundle (MySQL only) | `""` | | `dataStore.sql.rootCAPath` | Path to Root CA bundle. Supports MySQL and postgres. | `""` |
| `dataStore.sql.clientCertPath` | Path to client certificate (MySQL only) | `""` | | `dataStore.sql.clientCertPath` | Path to client certificate. Supports MySQL and postgres. | `""` |
| `dataStore.sql.clientKeyPath` | Path to private key for client certificate (MySQL only) | `""` | | `dataStore.sql.clientKeyPath` | Path to private key for client certificate. Supports MySQL and postgres. | `""` |
| `dataStore.sql.externalSecret.enabled` | Enable external secret for datastore creds | `false` | | `dataStore.sql.externalSecret.enabled` | Enable external secret for datastore creds | `false` |
| `dataStore.sql.externalSecret.name` | The name of the secret object | `""` | | `dataStore.sql.externalSecret.name` | The name of the secret object | `""` |
| `dataStore.sql.externalSecret.key` | The key of the secret object whose value is the dataStore.sql password | `""` | | `dataStore.sql.externalSecret.key` | The key of the secret object whose value is the dataStore.sql password | `""` |
@@ -263,6 +272,12 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `upstreamAuthority.awsSecret.keyFileArn` | ARN or name of the secret containing the intermediate CA private key | `""` | | `upstreamAuthority.awsSecret.keyFileArn` | ARN or name of the secret containing the intermediate CA private key | `""` |
| `upstreamAuthority.awsSecret.bundleFileArn` | (Optional) ARN or name of the secret containing the root CA bundle | `""` | | `upstreamAuthority.awsSecret.bundleFileArn` | (Optional) ARN or name of the secret containing the root CA bundle | `""` |
| `upstreamAuthority.awsSecret.assumeRoleArn` | (Optional) ARN of an IAM role to assume | `""` | | `upstreamAuthority.awsSecret.assumeRoleArn` | (Optional) ARN of an IAM role to assume | `""` |
| `upstreamAuthority.gcpCAS.enabled` | Flag to enable upstream authority plugin with GCP Certificate Authority Service | `false` |
| `upstreamAuthority.gcpCAS.projectName` | GCP project containing the root CA certificate | `""` |
| `upstreamAuthority.gcpCAS.regionName` | GCP region name (e.g., us-central1) | `""` |
| `upstreamAuthority.gcpCAS.caPool` | Name of the CA Pool that has the root CA certificate | `""` |
| `upstreamAuthority.gcpCAS.labelKey` | Label key used to filter and select the relevant CA certificate | `""` |
| `upstreamAuthority.gcpCAS.labelValue` | Label value used to filter and select the relevant CA certificate | `""` |
| `upstreamAuthority.certManager.enabled` | Flag to enable upstream authority plugin with cert manager | `false` | | `upstreamAuthority.certManager.enabled` | Flag to enable upstream authority plugin with cert manager | `false` |
| `upstreamAuthority.certManager.rbac.create` | Flag to create RBAC roles | `true` | | `upstreamAuthority.certManager.rbac.create` | Flag to create RBAC roles | `true` |
| `upstreamAuthority.certManager.issuerName` | Defaults to the release name, override if CA is provided outside of the chart | `""` | | `upstreamAuthority.certManager.issuerName` | Defaults to the release name, override if CA is provided outside of the chart | `""` |
@@ -307,6 +322,7 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `controllerManager.staticManifestMode` | Flag to configure static mode. Valid options off, internal, and external. If internal, the identities config options will be rendered to an included configmap | `off` | | `controllerManager.staticManifestMode` | Flag to configure static mode. Valid options off, internal, and external. If internal, the identities config options will be rendered to an included configmap | `off` |
| `controllerManager.className` | specify to use an explicit class name. If empty, it will be automatically set to Release.Namespace-Release.Name to not conflict with other installs, enabling parallel installs. | `""` | | `controllerManager.className` | specify to use an explicit class name. If empty, it will be automatically set to Release.Namespace-Release.Name to not conflict with other installs, enabling parallel installs. | `""` |
| `controllerManager.watchClassless` | specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. | `false` | | `controllerManager.watchClassless` | specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. | `false` |
| `controllerManager.filterByClassName` | Restrict the ClusterSPIFFEID cache to this controller's className. Only enable after confirming target ClusterSPIFFEIDs already carry the className label, or existing registrations will be deleted. | `false` |
| `controllerManager.entryIDPrefixCleanup` | Sets which entry prefixes to remove for migrations. Consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. | `false` | | `controllerManager.entryIDPrefixCleanup` | Sets which entry prefixes to remove for migrations. Consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. | `false` |
| `controllerManager.addEntryIDPrefix` | If true, prepends the clusterName to the entryID of each entry the controller manager registers. | `true` | | `controllerManager.addEntryIDPrefix` | If true, prepends the clusterName to the entryID of each entry the controller manager registers. | `true` |
| `controllerManager.gcInterval` | How often the SPIRE state is reconciled when the controller is otherwise idle. This impacts how quickly SPIRE state will converge after CRDs are removed or SPIRE state is mutated underneath the controller. Values are in nanoseconds. | `10000000000` | | `controllerManager.gcInterval` | How often the SPIRE state is reconciled when the controller is otherwise idle. This impacts how quickly SPIRE state will converge after CRDs are removed or SPIRE state is mutated underneath the controller. Values are in nanoseconds. | `10000000000` |
@@ -396,6 +412,7 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `externalControllerManagers.defaults.reconcile.clusterFederatedTrustDomains` | Enable reconciliation of clusterFederatedTrustDomains from K8s to the SPIRE server | `false` | | `externalControllerManagers.defaults.reconcile.clusterFederatedTrustDomains` | Enable reconciliation of clusterFederatedTrustDomains from K8s to the SPIRE server | `false` |
| `externalControllerManagers.defaults.className` | specify to use an explicit class name. If empty, it will be automatically set to Release.Namespace-Release.Name to not conflict with other installs, enabling parallel installs. | `""` | | `externalControllerManagers.defaults.className` | specify to use an explicit class name. If empty, it will be automatically set to Release.Namespace-Release.Name to not conflict with other installs, enabling parallel installs. | `""` |
| `externalControllerManagers.defaults.watchClassless` | specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. | `false` | | `externalControllerManagers.defaults.watchClassless` | specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. | `false` |
| `externalControllerManagers.defaults.filterByClassName` | Restrict the ClusterSPIFFEID cache to this controller's className. Only enable after confirming target ClusterSPIFFEIDs already carry the className label, or existing registrations will be deleted. | `false` |
| `externalControllerManagers.defaults.entryIDPrefixCleanup` | consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. | `false` | | `externalControllerManagers.defaults.entryIDPrefixCleanup` | consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. | `false` |
| `externalControllerManagers.defaults.parentIDTemplate` | The template that is used to register workloads. | `spiffe://{{ .TrustDomain }}/spire/agent/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` | | `externalControllerManagers.defaults.parentIDTemplate` | The template that is used to register workloads. | `spiffe://{{ .TrustDomain }}/spire/agent/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}` |
| `externalControllerManagers.defaults.leaderElection.leaseDuration` | Duration that non-leader candidates will wait to force acquire leadership. Increase this in high-load clusters to reduce API server pressure. | `15s` | | `externalControllerManagers.defaults.leaderElection.leaseDuration` | Duration that non-leader candidates will wait to force acquire leadership. Increase this in high-load clusters to reduce API server pressure. | `15s` |
@@ -495,7 +512,10 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `nodeAttestor.gcpIIT.metadataValueMaxSize` | Sets the maximum metadata value size considered by the plugin for selectors | `0` | | `nodeAttestor.gcpIIT.metadataValueMaxSize` | Sets the maximum metadata value size considered by the plugin for selectors | `0` |
| `nodeAttestor.gcpIIT.agentPathTemplate` | A URL path portion format of Agent's SPIFFE ID. Describe in text/template format. | `""` | | `nodeAttestor.gcpIIT.agentPathTemplate` | A URL path portion format of Agent's SPIFFE ID. Describe in text/template format. | `""` |
| `nodeAttestor.x509POP.enabled` | Enable the x509_popg node attestor | `false` | | `nodeAttestor.x509POP.enabled` | Enable the x509_popg node attestor | `false` |
| `nodeAttestor.x509POP.mode` | What mode to set the plugin to. Currently only spiffe mode is supported | `spiffe` | | `nodeAttestor.x509POP.mode` | Plugin mode: spiffe (exchange) or externalPKI (enrollment CA bundle) | `spiffe` |
| `nodeAttestor.x509POP.caBundle` | CA bundle for externalPKI mode. Provide inline PEM contents or reference an existing ConfigMap. | |
| `nodeAttestor.x509POP.caBundle.bundle` | PEM CA bundle contents. When set, the chart creates and mounts a ConfigMap. | `""` |
| `nodeAttestor.x509POP.caBundle.existingConfigMap` | Name of a ConfigMap containing a `ca-bundle.pem` key with the PEM CA bundle. | `""` |
| `nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` | | `nodeAttestor.x509POP.spiffePrefix` | What prefix to use when mode is spiffe | `/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/` |
| `nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `""` | | `nodeAttestor.x509POP.agentPathTemplate` | Override the default agent path template | `""` |
| `nodeAttestor.x509POP.maxIntermediates` | Maximum number of intermediate certificates allowed in the certificate chain | `4` | | `nodeAttestor.x509POP.maxIntermediates` | Maximum number of intermediate certificates allowed in the certificate chain | `4` |
@@ -622,5 +642,11 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `tests.bash.image.pullPolicy` | The image pull policy | `IfNotPresent` | | `tests.bash.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `tests.bash.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:90041f375e30f41aa7e0390075d8a69dc61900771d52fa98d63ee5d03d866a58` | | `tests.bash.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:90041f375e30f41aa7e0390075d8a69dc61900771d52fa98d63ee5d03d866a58` |
| `kubeConfigs` | Manage additional kubeconfig files to talk to external Kubernetes clusters | `{}` | | `kubeConfigs` | Manage additional kubeconfig files to talk to external Kubernetes clusters | `{}` |
| `jwtSVIDExecConfig.image.registry` | The OCI registry to pull the exec credential plugin image from | `ghcr.io` |
| `jwtSVIDExecConfig.image.repository` | The repository within the registry | `spiffe/k8s-spiffe-workload-jwt-exec-auth` |
| `jwtSVIDExecConfig.image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `jwtSVIDExecConfig.image.tag` | Overrides the image tag | `0.2.0` |
| `jwtSVIDExecConfig.pluginPath` | The path of the plugin binary inside the plugin image, staged for exec by the kubeConfigs consumers | `/ko-app/cmd` |
| `jwtSVIDExecConfig.spiffeID` | The SPIFFE ID the plugin mints a JWT-SVID for; a full spiffe:// URI, or a "/"-prefixed path expanded with the chart trust domain (e.g. /spire-root); required when any kubeConfigs entry uses jwtSVIDExec | `/spire-root` |
| `spireIdentityExchange.enabled` | Enable the server side of the SPIRE Identity Exchange system | `false` | | `spireIdentityExchange.enabled` | Enable the server side of the SPIRE Identity Exchange system | `false` |
| `spike.enabled` | Enable the server side of SPIKE | `false` | | `spike.enabled` | Enable the server side of SPIKE | `false` |
@@ -173,6 +173,14 @@ Auto-generation preserves trailing numbers from cluster names or uses hash for u
subPath: {{ . }} subPath: {{ . }}
readOnly: true readOnly: true
{{- end }} {{- end }}
{{- if hasKey . "kubeConfig" }}
{{- $entry := default dict (index .Values.kubeConfigs .kubeConfig) }}
{{- if hasKey $entry "jwtSVIDExec" }}
- name: plugins
mountPath: /plugins
readOnly: true
{{- end }}
{{- end }}
- name: spire-controller-manager-tmp - name: spire-controller-manager-tmp
mountPath: /tmp mountPath: /tmp
subPath: {{ printf "spire-controller-manager%s" .suffix }} subPath: {{ printf "spire-controller-manager%s" .suffix }}
@@ -186,6 +186,63 @@ Name of the chart-generated Secret holding the inline kubeConfigs entries.
{{ include "spire-server.fullname" . }}-kubeconfigs {{ include "spire-server.fullname" . }}-kubeconfigs
{{- end }} {{- end }}
{{/*
Path of the staged jwt-svid exec plugin binary inside the shared plugins volume. Used both as the
init-container copy target and as the exec kubeconfig command, so the two must stay in sync.
*/}}
{{- define "spire-server.jwt-svid-exec-binary-path" -}}
/plugins/jwt-svid-exec
{{- end }}
{{- define "spire-server.jwt-svid-exec-kubeconfig" -}}
{{- $jwtSVIDExec := .jwtSVIDExec -}}
{{- $root := .root -}}
{{- $spiffeID := $root.Values.jwtSVIDExecConfig.spiffeID -}}
{{- if not $spiffeID -}}
{{- fail "jwtSVIDExecConfig.spiffeID is required when a kubeConfigs entry uses jwtSVIDExec" -}}
{{- end -}}
{{- $chartTD := include "spire-lib.trust-domain" $root -}}
{{- if hasPrefix "/" $spiffeID -}}
{{- $spiffeID = printf "spiffe://%s%s" $chartTD $spiffeID -}}
{{- else if hasPrefix "spiffe://" $spiffeID -}}
{{- $idTD := $spiffeID | trimPrefix "spiffe://" | splitList "/" | first -}}
{{- if ne $idTD $chartTD -}}
{{- fail (printf "jwtSVIDExecConfig.spiffeID trust domain %q must match the chart trust domain %q" $idTD $chartTD) -}}
{{- end -}}
{{- else -}}
{{- fail (printf "jwtSVIDExecConfig.spiffeID %q must be a spiffe:// URI or a path starting with \"/\"" $spiffeID) -}}
{{- end -}}
apiVersion: v1
kind: Config
clusters:
- name: cluster
cluster:
server: {{ $jwtSVIDExec.server | quote }}
certificate-authority-data: {{ $jwtSVIDExec.certificateAuthorityData | quote }}
users:
- name: spiffe
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: {{ include "spire-server.jwt-svid-exec-binary-path" $root }}
interactiveMode: Never
env:
- name: SPIFFE_JWT_SOURCE
value: "server-admin-api"
- name: SPIRE_SERVER_SOCKET
value: "unix:///tmp/spire-server/private/api.sock"
- name: SPIFFE_ID
value: {{ $spiffeID | quote }}
- name: SPIFFE_JWT_AUDIENCE
value: {{ $jwtSVIDExec.audience | default "k8s" | quote }}
contexts:
- name: cluster
context:
cluster: cluster
user: spiffe
current-context: cluster
{{- end }}
{{- define "spire-server.serviceAccountAllowedList" }} {{- define "spire-server.serviceAccountAllowedList" }}
{{- $releaseNamespace := include "spire-server.agent-namespace" . }} {{- $releaseNamespace := include "spire-server.agent-namespace" . }}
{{- if ne (len .Values.nodeAttestor.k8sPSAT.serviceAccountAllowList) 0 }} {{- if ne (len .Values.nodeAttestor.k8sPSAT.serviceAccountAllowList) 0 }}
@@ -244,14 +301,35 @@ Name of the chart-generated Secret holding the inline kubeConfigs entries.
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- define "spire-server.datastore-is-postgres" -}}
{{- or (eq .Values.dataStore.sql.databaseType "postgres") (eq .Values.dataStore.sql.databaseType "aws_postgres") -}}
{{- end }}
{{- define "spire-server.datastore-postgres-passwordless" -}}
{{- $isPostgres := eq (include "spire-server.datastore-is-postgres" .) "true" -}}
{{- and $isPostgres (eq .Values.dataStore.sql.password "") (not .Values.dataStore.sql.externalSecret.enabled) -}}
{{- end }}
{{- define "spire-server.datastore-postgres-ro-passwordless" -}}
{{- $isPostgres := eq (include "spire-server.datastore-is-postgres" .) "true" -}}
{{- and $isPostgres (eq .Values.dataStore.sql.readOnly.password "") (not .Values.dataStore.sql.readOnly.externalSecret.enabled) -}}
{{- end }}
{{- define "spire-server.datastore-config" }} {{- define "spire-server.datastore-config" }}
{{- $config := dict }} {{- $config := dict }}
{{- $pw := "" }} {{- $pw := "" }}
{{- $ropw := "" }} {{- $ropw := "" }}
{{- if eq .Values.dataStore.sql.databaseType "sqlite3" }} {{- if eq .Values.dataStore.sql.databaseType "sqlite3" }}
{{- $_ := set $config "database_type" "sqlite3" }} {{- $_ := set $config "database_type" "sqlite3" }}
{{- if .Values.dataStore.sql.inMemory }}
{{- /* cache=shared is not optional: without it every pooled connection opens its own
empty database, so the server silently loses every write it did not make itself. */}}
{{- $query := include "spire-server.config-sqlite-query" (concat (list (dict "mode" "memory") (dict "cache" "shared")) .Values.dataStore.sql.options) }}
{{- $_ := set $config "connection_string" (printf "memdb%s" $query) }}
{{- else }}
{{- $query := include "spire-server.config-sqlite-query" .Values.dataStore.sql.options }} {{- $query := include "spire-server.config-sqlite-query" .Values.dataStore.sql.options }}
{{- $_ := set $config "connection_string" (printf "%s%s" .Values.dataStore.sql.file $query) }} {{- $_ := set $config "connection_string" (printf "%s%s" .Values.dataStore.sql.file $query) }}
{{- end }}
{{- else if or (eq .Values.dataStore.sql.databaseType "mysql") (eq .Values.dataStore.sql.databaseType "aws_mysql") (eq .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") }} {{- else if or (eq .Values.dataStore.sql.databaseType "mysql") (eq .Values.dataStore.sql.databaseType "aws_mysql") (eq .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") }}
{{- if eq .Values.dataStore.sql.databaseType "mysql" }} {{- if eq .Values.dataStore.sql.databaseType "mysql" }}
{{- $_ := set $config "database_type" "mysql" }} {{- $_ := set $config "database_type" "mysql" }}
@@ -285,18 +363,32 @@ Name of the chart-generated Secret holding the inline kubeConfigs entries.
{{- else if or (eq .Values.dataStore.sql.databaseType "postgres") (eq .Values.dataStore.sql.databaseType "aws_postgres") }} {{- else if or (eq .Values.dataStore.sql.databaseType "postgres") (eq .Values.dataStore.sql.databaseType "aws_postgres") }}
{{- if eq .Values.dataStore.sql.databaseType "postgres" }} {{- if eq .Values.dataStore.sql.databaseType "postgres" }}
{{- $_ := set $config "database_type" "postgres" }} {{- $_ := set $config "database_type" "postgres" }}
{{- $pw = " password=${DBPW}" }}
{{- $ropw = " password=${RODBPW}" }}
{{- else }} {{- else }}
{{- $_ := set $config "database_type" (list (dict "aws_postgres" (dict "region" .Values.dataStore.sql.region))) }} {{- $_ := set $config "database_type" (list (dict "aws_postgres" (dict "region" .Values.dataStore.sql.region))) }}
{{- end }} {{- end }}
{{- if ne (include "spire-server.datastore-postgres-passwordless" .) "true" }}
{{- $pw = " password=${DBPW}" }}
{{- end }}
{{- if ne (include "spire-server.datastore-postgres-ro-passwordless" .) "true" }}
{{- $ropw = " password=${RODBPW}" }}
{{- end }}
{{- $sslPaths := "" }}
{{- if ne .Values.dataStore.sql.rootCAPath "" }}
{{- $sslPaths = printf "%s sslrootcert=%s" $sslPaths .Values.dataStore.sql.rootCAPath }}
{{- end }}
{{- if ne .Values.dataStore.sql.clientCertPath "" }}
{{- $sslPaths = printf "%s sslcert=%s" $sslPaths .Values.dataStore.sql.clientCertPath }}
{{- end }}
{{- if ne .Values.dataStore.sql.clientKeyPath "" }}
{{- $sslPaths = printf "%s sslkey=%s" $sslPaths .Values.dataStore.sql.clientKeyPath }}
{{- end }}
{{- $port := int .Values.dataStore.sql.port | default 5432 }} {{- $port := int .Values.dataStore.sql.port | default 5432 }}
{{- $options:= include "spire-server.config-postgresql-options" .Values.dataStore.sql.options }} {{- $options:= include "spire-server.config-postgresql-options" .Values.dataStore.sql.options }}
{{- $_ := set $config "connection_string" (printf "dbname=%s user=%s%s host=%s port=%d%s" .Values.dataStore.sql.databaseName .Values.dataStore.sql.username $pw .Values.dataStore.sql.host $port $options) }} {{- $_ := set $config "connection_string" (printf "dbname=%s user=%s%s host=%s port=%d%s%s" .Values.dataStore.sql.databaseName .Values.dataStore.sql.username $pw .Values.dataStore.sql.host $port $options $sslPaths) }}
{{- if .Values.dataStore.sql.readOnly.enabled }} {{- if .Values.dataStore.sql.readOnly.enabled }}
{{- $roPort := int .Values.dataStore.sql.readOnly.port | default 5432 }} {{- $roPort := int .Values.dataStore.sql.readOnly.port | default 5432 }}
{{- $roOptions:= include "spire-server.config-postgresql-options" .Values.dataStore.sql.readOnly.options }} {{- $roOptions:= include "spire-server.config-postgresql-options" .Values.dataStore.sql.readOnly.options }}
{{- $_ := set $config "ro_connection_string" (printf "dbname=%s user=%s%s host=%s port=%d%s" .Values.dataStore.sql.readOnly.databaseName .Values.dataStore.sql.readOnly.username $ropw .Values.dataStore.sql.readOnly.host $roPort $roOptions) }} {{- $_ := set $config "ro_connection_string" (printf "dbname=%s user=%s%s host=%s port=%d%s%s" .Values.dataStore.sql.readOnly.databaseName .Values.dataStore.sql.readOnly.username $ropw .Values.dataStore.sql.readOnly.host $roPort $roOptions $sslPaths) }}
{{- end }} {{- end }}
{{- else }} {{- else }}
{{- fail "Unsupported database type" }} {{- fail "Unsupported database type" }}
@@ -412,12 +504,27 @@ The code below determines what connection type should be used.
{{- default .Values.caSubject.commonName $g }} {{- default .Values.caSubject.commonName $g }}
{{- end }} {{- end }}
{{- define "spire-server.external-server-subject-kind" -}}
{{- $kind := .Values.externalServerSubject.kind | default "User" }}
{{- if not (has $kind (list "User" "Group" "ServiceAccount")) }}
{{- fail (printf "Unknown externalServerSubject.kind: %s (must be \"User\", \"Group\", or \"ServiceAccount\")" $kind) }}
{{- end }}
{{- $kind }}
{{- end }}
{{- define "spire-server.subject" }} {{- define "spire-server.subject" }}
subjects: subjects:
{{- if .Values.externalServer }} {{- if .Values.externalServer }}
{{- $kind := include "spire-server.external-server-subject-kind" . }}
{{- if eq $kind "ServiceAccount" }}
- kind: ServiceAccount
name: {{ .Values.externalServerSubject.name | quote }}
namespace: {{ .Values.externalServerSubject.namespace | default (include "spire-server.namespace" .) | quote }}
{{- else }}
- apiGroup: rbac.authorization.k8s.io - apiGroup: rbac.authorization.k8s.io
kind: User kind: {{ $kind }}
name: spire-root name: {{ .Values.externalServerSubject.name | quote }}
{{- end }}
{{- else }} {{- else }}
- kind: ServiceAccount - kind: ServiceAccount
name: {{ include "spire-server.serviceAccountName" . }} name: {{ include "spire-server.serviceAccountName" . }}
@@ -173,6 +173,7 @@ plugins:
sql: sql:
plugin_data: plugin_data:
{{ include "spire-server.datastore-config" . | nindent 8 }} {{ include "spire-server.datastore-config" . | nindent 8 }}
{{- if or (eq .Values.dataStore.sql.databaseType "mysql") (eq .Values.dataStore.sql.databaseType "aws_mysql") }}
{{- if ne .Values.dataStore.sql.rootCAPath "" }} {{- if ne .Values.dataStore.sql.rootCAPath "" }}
root_ca_path: {{ .Values.dataStore.sql.rootCAPath }} root_ca_path: {{ .Values.dataStore.sql.rootCAPath }}
{{- end }} {{- end }}
@@ -180,7 +181,8 @@ plugins:
client_cert_path: {{ .Values.dataStore.sql.clientCertPath }} client_cert_path: {{ .Values.dataStore.sql.clientCertPath }}
{{- end }} {{- end }}
{{- if ne .Values.dataStore.sql.clientKeyPath "" }} {{- if ne .Values.dataStore.sql.clientKeyPath "" }}
client_key_path : {{ .Values.dataStore.sql.clientKeyPath }} client_key_path: {{ .Values.dataStore.sql.clientKeyPath }}
{{- end }}
{{- end }} {{- end }}
max_open_conns: {{ .Values.dataStore.sql.maxOpenConns }} max_open_conns: {{ .Values.dataStore.sql.maxOpenConns }}
max_idle_conns: {{ .Values.dataStore.sql.maxIdleConns }} max_idle_conns: {{ .Values.dataStore.sql.maxIdleConns }}
@@ -281,6 +283,12 @@ plugins:
{{- if or (eq (.enabled | toString) "true") $root.Values.spireIdentityExchange.enabled }} {{- if or (eq (.enabled | toString) "true") $root.Values.spireIdentityExchange.enabled }}
x509pop: x509pop:
plugin_data: plugin_data:
{{- if eq .mode "externalPKI" }}
mode: external_pki
ca_bundle_path: "/run/spire/data/x509pop-ca-bundle.pem"
max_intermediates: {{ .maxIntermediates }}
max_rsa_key_size: {{ .maxRSAKeySize }}
{{- else }}
mode: {{ .mode }} mode: {{ .mode }}
spiffe_prefix: {{ include "spire-server.identity-exchange-spiffe-prefix" $root | quote }} spiffe_prefix: {{ include "spire-server.identity-exchange-spiffe-prefix" $root | quote }}
max_intermediates: {{ .maxIntermediates }} max_intermediates: {{ .maxIntermediates }}
@@ -298,6 +306,7 @@ plugins:
{{- $cn = printf "/%s" (include "spire-lib.cluster-name" $root) }} {{- $cn = printf "/%s" (include "spire-lib.cluster-name" $root) }}
{{- end }} {{- end }}
agent_path_template: {{ replace "${HELM_ADD_CLUSTER_NAME}" $cn $agentPathTemplate | quote }} agent_path_template: {{ replace "${HELM_ADD_CLUSTER_NAME}" $cn $agentPathTemplate | quote }}
{{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- with .Values.nodeAttestor.awsIID }} {{- with .Values.nodeAttestor.awsIID }}
@@ -649,6 +658,22 @@ plugins:
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- with .Values.upstreamAuthority.gcpCAS }}
{{- if eq (.enabled | toString) "true" }}
{{- $upstreamAuthorityUsed = add1 $upstreamAuthorityUsed }}
UpstreamAuthority:
gcp_cas:
plugin_data:
root_cert_spec:
project_name: {{ .projectName | quote }}
region_name: {{ .regionName | quote }}
ca_pool: {{ .caPool | quote }}
label_key: {{ .labelKey | quote }}
label_value: {{ .labelValue | quote }}
{{- end }}
{{- end }}
{{- if gt $upstreamAuthorityUsed 1 }} {{- if gt $upstreamAuthorityUsed 1 }}
{{- fail "You can only enable a single Upstream Authority." }} {{- fail "You can only enable a single Upstream Authority." }}
{{- end }} {{- end }}
@@ -91,6 +91,7 @@ ignoreNamespaces:
spireServerSocketPath: "/tmp/spire-server/private/api.sock" spireServerSocketPath: "/tmp/spire-server/private/api.sock"
className: {{ include "spire-server.controller-manager-class-name" . | quote}} className: {{ include "spire-server.controller-manager-class-name" . | quote}}
watchClassless: {{ if hasKey .settings "watchClassless" }}{{ .settings.watchClassless | toYaml }}{{ else }}{{ .defaults.watchClassless | toYaml }}{{ end }} watchClassless: {{ if hasKey .settings "watchClassless" }}{{ .settings.watchClassless | toYaml }}{{ else }}{{ .defaults.watchClassless | toYaml }}{{ end }}
filterByClassName: {{ if hasKey .settings "filterByClassName" }}{{ .settings.filterByClassName | toYaml }}{{ else }}{{ .defaults.filterByClassName | toYaml }}{{ end }}
parentIDTemplate: {{ if hasKey .settings "parentIDTemplate" }}{{ .settings.parentIDTemplate | quote }}{{ else }}{{ .defaults.parentIDTemplate | quote }}{{ end }} parentIDTemplate: {{ if hasKey .settings "parentIDTemplate" }}{{ .settings.parentIDTemplate | quote }}{{ else }}{{ .defaults.parentIDTemplate | quote }}{{ end }}
{{- $reconcile := dict }} {{- $reconcile := dict }}
{{- if hasKey .settings "reconcile" }} {{- if hasKey .settings "reconcile" }}
@@ -1,3 +1,4 @@
{{- $installAndUpgradeHooksEnabled := dig "installAndUpgradeHooks" "enabled" .Values.controllerManager.installAndUpgradeHook.enabled .Values.global }}
{{- if not .Values.externalServer }} {{- if not .Values.externalServer }}
{{- if eq .Values.controllerManager.staticManifestMode "off" }} {{- if eq .Values.controllerManager.staticManifestMode "off" }}
{{- if and (eq (.Values.controllerManager.enabled | toString) "true") .Values.controllerManager.validatingWebhookConfiguration.enabled }} {{- if and (eq (.Values.controllerManager.enabled | toString) "true") .Values.controllerManager.validatingWebhookConfiguration.enabled }}
@@ -12,7 +13,7 @@ webhooks:
name: {{ include "spire-controller-manager.fullname" . }}-webhook name: {{ include "spire-controller-manager.fullname" . }}-webhook
namespace: {{ include "spire-server.namespace" . }} namespace: {{ include "spire-server.namespace" . }}
path: /validate-spire-spiffe-io-v1alpha1-clusterfederatedtrustdomain path: /validate-spire-spiffe-io-v1alpha1-clusterfederatedtrustdomain
{{- if eq (.Values.controllerManager.installAndUpgradeHook.enabled | toString) "true" }} {{- if eq ($installAndUpgradeHooksEnabled | toString) "true" }}
failurePolicy: Ignore # Actual value to be set by post install/upgrade hooks failurePolicy: Ignore # Actual value to be set by post install/upgrade hooks
{{- else }} {{- else }}
failurePolicy: {{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }} failurePolicy: {{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}
@@ -30,7 +31,11 @@ webhooks:
name: {{ include "spire-controller-manager.fullname" . }}-webhook name: {{ include "spire-controller-manager.fullname" . }}-webhook
namespace: {{ include "spire-server.namespace" . }} namespace: {{ include "spire-server.namespace" . }}
path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid path: /validate-spire-spiffe-io-v1alpha1-clusterspiffeid
{{- if eq ($installAndUpgradeHooksEnabled | toString) "true" }}
failurePolicy: Ignore # Actual value to be set by post install/upgrade hooks failurePolicy: Ignore # Actual value to be set by post install/upgrade hooks
{{- else }}
failurePolicy: {{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}
{{- end }}
name: vclusterspiffeid.kb.io name: vclusterspiffeid.kb.io
rules: rules:
- apiGroups: ["spire.spiffe.io"] - apiGroups: ["spire.spiffe.io"]
@@ -6,8 +6,9 @@
{{- if hasKey $value "kubeConfig" }}{{ $present = append $present "kubeConfig" }}{{- end }} {{- if hasKey $value "kubeConfig" }}{{ $present = append $present "kubeConfig" }}{{- end }}
{{- if hasKey $value "kubeConfigBase64" }}{{ $present = append $present "kubeConfigBase64" }}{{- end }} {{- if hasKey $value "kubeConfigBase64" }}{{ $present = append $present "kubeConfigBase64" }}{{- end }}
{{- if hasKey $value "externalSecret" }}{{ $present = append $present "externalSecret" }}{{- end }} {{- if hasKey $value "externalSecret" }}{{ $present = append $present "externalSecret" }}{{- end }}
{{- if hasKey $value "jwtSVIDExec" }}{{ $present = append $present "jwtSVIDExec" }}{{- end }}
{{- if ne (len $present) 1 }} {{- if ne (len $present) 1 }}
{{- fail (printf "kubeConfigs entry %q must set exactly one of kubeConfig, kubeConfigBase64, or externalSecret (got: %v)" $name $present) }} {{- fail (printf "kubeConfigs entry %q must set exactly one of kubeConfig, kubeConfigBase64, externalSecret, or jwtSVIDExec (got: %v)" $name $present) }}
{{- end }} {{- end }}
{{- if hasKey $value "externalSecret" }} {{- if hasKey $value "externalSecret" }}
{{- if not $value.externalSecret.name }} {{- if not $value.externalSecret.name }}
@@ -30,6 +31,8 @@ data:
{{- range $name, $value := $inline }} {{- range $name, $value := $inline }}
{{- if hasKey $value "kubeConfig" }} {{- if hasKey $value "kubeConfig" }}
{{ $name }}: {{ $value.kubeConfig | b64enc }} {{ $name }}: {{ $value.kubeConfig | b64enc }}
{{- else if hasKey $value "jwtSVIDExec" }}
{{ $name }}: {{ include "spire-server.jwt-svid-exec-kubeconfig" (dict "jwtSVIDExec" $value.jwtSVIDExec "root" $root) | b64enc }}
{{- else }} {{- else }}
{{ $name }}: {{ $value.kubeConfigBase64 | nospace }} {{ $name }}: {{ $value.kubeConfigBase64 | nospace }}
{{- end }} {{- end }}
@@ -0,0 +1,23 @@
{{- if not .Values.externalServer }}
{{- if .Values.podDisruptionBudget.enabled }}
{{- if and .Values.podDisruptionBudget.minAvailable .Values.podDisruptionBudget.maxUnavailable }}
{{- fail "podDisruptionBudget.minAvailable and podDisruptionBudget.maxUnavailable are mutually exclusive" }}
{{- end }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "spire-server.fullname" . }}
namespace: {{ include "spire-server.namespace" . }}
labels:
{{- include "spire-server.labels" . | nindent 4 }}
spec:
{{- if .Values.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.podDisruptionBudget.minAvailable | default (max 1 (sub .Values.replicaCount 1)) }}
{{- end }}
selector:
matchLabels:
{{- include "spire-server.selectorLabels" . | nindent 6 }}
{{- end }}
{{- end }}
@@ -85,11 +85,11 @@ spec:
{ {
"webhooks":[ "webhooks":[
{ {
"name":"vclusterspiffeid.kb.io", "name":"vclusterfederatedtrustdomain.kb.io",
"failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}" "failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}"
}, },
{ {
"name":"vclusterfederatedtrustdomain.kb.io", "name":"vclusterspiffeid.kb.io",
"failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}" "failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}"
} }
] ]
@@ -85,11 +85,11 @@ spec:
{ {
"webhooks":[ "webhooks":[
{ {
"name":"vclusterspiffeid.kb.io", "name":"vclusterfederatedtrustdomain.kb.io",
"failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}" "failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}"
}, },
{ {
"name":"vclusterfederatedtrustdomain.kb.io", "name":"vclusterspiffeid.kb.io",
"failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}" "failurePolicy":"{{ .Values.controllerManager.validatingWebhookConfiguration.failurePolicy }}"
} }
] ]
@@ -85,11 +85,11 @@ spec:
{ {
"webhooks":[ "webhooks":[
{ {
"name":"vclusterspiffeid.kb.io", "name":"vclusterfederatedtrustdomain.kb.io",
"failurePolicy":"Ignore" "failurePolicy":"Ignore"
}, },
{ {
"name":"vclusterfederatedtrustdomain.kb.io", "name":"vclusterspiffeid.kb.io",
"failurePolicy":"Ignore" "failurePolicy":"Ignore"
} }
] ]
@@ -7,7 +7,8 @@
{{- if and (.Values.dataStore.sql.externalSecret.enabled) (eq .Values.dataStore.sql.externalSecret.key "") }} {{- if and (.Values.dataStore.sql.externalSecret.enabled) (eq .Values.dataStore.sql.externalSecret.key "") }}
{{- fail "dataStore.sql.externalSecret.key cannot be empty string when dataStore.sql.externalSecret is enabled" }} {{- fail "dataStore.sql.externalSecret.key cannot be empty string when dataStore.sql.externalSecret is enabled" }}
{{- end }} {{- end }}
{{- if and (ne .Values.dataStore.sql.databaseType "sqlite3") (not .Values.dataStore.sql.externalSecret.enabled) (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") }} {{- $postgresPasswordless := eq (include "spire-server.datastore-postgres-passwordless" .) "true" }}
{{- if and (ne .Values.dataStore.sql.databaseType "sqlite3") (not .Values.dataStore.sql.externalSecret.enabled) (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") (not $postgresPasswordless) }}
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
@@ -41,8 +41,14 @@
{{- if (has .Values.persistence.type (list "pvc" "hostPath")) }} {{- if (has .Values.persistence.type (list "pvc" "hostPath")) }}
{{- fail "When running as deployment, persistence can't be set. 'persistence.type' must be [\"emptyDir\"]" }} {{- fail "When running as deployment, persistence can't be set. 'persistence.type' must be [\"emptyDir\"]" }}
{{- end }} {{- end }}
{{- if (eq .Values.dataStore.sql.databaseType "sqlite3") }} {{- if and (eq .Values.dataStore.sql.databaseType "sqlite3") (not .Values.dataStore.sql.inMemory) }}
{{- fail "When running as deployment, sqlite3 can't be used." }} {{- fail "When running as deployment, sqlite3 can only be used in memory. Set 'dataStore.sql.inMemory' to true." }}
{{- end }}
{{- if and (eq .Values.dataStore.sql.databaseType "sqlite3") .Values.dataStore.sql.inMemory }}
{{- $surge := dig "rollingUpdate" "maxSurge" "" .Values.updateStrategy | toString }}
{{- if not (or (eq (dig "type" "" .Values.updateStrategy) "Recreate") (eq $surge "0") (eq $surge "0%")) }}
{{- fail "An in-memory datastore on a deployment must not surge, or two servers run with separate datastores. Set 'updateStrategy' to {type: Recreate} or {rollingUpdate: {maxSurge: 0}}." }}
{{- end }}
{{- end }} {{- end }}
{{- if (eq (.Values.keyManager.disk.enabled | toString) "true") }} {{- if (eq (.Values.keyManager.disk.enabled | toString) "true") }}
{{- fail "When running as deployment, disk keymanager can't be used. 'keyManager.disk.enabled' must be false." }} {{- fail "When running as deployment, disk keymanager can't be used. 'keyManager.disk.enabled' must be false." }}
@@ -53,19 +59,27 @@
{{- if hasKey .Values.dataStore.sql "plugin_data" }} {{- if hasKey .Values.dataStore.sql "plugin_data" }}
{{- fail "The plugin_data setting to the sql data store is no longer supported." }} {{- fail "The plugin_data setting to the sql data store is no longer supported." }}
{{- end }} {{- end }}
{{- if and (ne .Values.dataStore.sql.databaseType "mysql") (ne .Values.dataStore.sql.databaseType "aws_mysql") }} {{- $certPathDatabaseType := or (eq .Values.dataStore.sql.databaseType "mysql") (eq .Values.dataStore.sql.databaseType "aws_mysql") (eq .Values.dataStore.sql.databaseType "postgres") (eq .Values.dataStore.sql.databaseType "aws_postgres") }}
{{- if not $certPathDatabaseType }}
{{- if ne .Values.dataStore.sql.rootCAPath "" }} {{- if ne .Values.dataStore.sql.rootCAPath "" }}
{{- fail "rootCAPath can only be set with database type mysql or aws_mysql." }} {{- fail "rootCAPath can only be set with database type mysql, aws_mysql, postgres or aws_postgres." }}
{{- end }} {{- end }}
{{- if ne .Values.dataStore.sql.clientCertPath "" }} {{- if ne .Values.dataStore.sql.clientCertPath "" }}
{{- fail "clientCertPath can only be set with database type mysql or aws_mysql." }} {{- fail "clientCertPath can only be set with database type mysql, aws_mysql, postgres or aws_postgres." }}
{{- end }} {{- end }}
{{- if ne .Values.dataStore.sql.clientKeyPath "" }} {{- if ne .Values.dataStore.sql.clientKeyPath "" }}
{{- fail "clientKeyPath can only be set with database type mysql or aws_mysql." }} {{- fail "clientKeyPath can only be set with database type mysql, aws_mysql, postgres or aws_postgres." }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if and (or (eq .Values.dataStore.sql.databaseType "postgres") (eq .Values.dataStore.sql.databaseType "aws_postgres")) (ne .Values.dataStore.sql.password "") (ne .Values.dataStore.sql.clientCertPath "") }}
{{- fail "dataStore.sql.password and dataStore.sql.clientCertPath are mutually exclusive for postgres; use one authentication method." }}
{{- end }}
{{- $pluginsToLoad := include "spire-lib.extract_custom_plugin_images" . | fromYamlArray }} {{- $pluginsToLoad := include "spire-lib.extract_custom_plugin_images" . | fromYamlArray }}
{{- $pluginLoaderNeeded := or .Values.credentialComposer.cel.enabled .Values.spireIdentityExchange.enabled (gt (len $pluginsToLoad) 0) }} {{- $jwtExecNeeded := false }}
{{- range $name, $value := .Values.kubeConfigs }}
{{- if hasKey $value "jwtSVIDExec" }}{{ $jwtExecNeeded = true }}{{- end }}
{{- end }}
{{- $pluginLoaderNeeded := or .Values.credentialComposer.cel.enabled .Values.spireIdentityExchange.enabled (gt (len $pluginsToLoad) 0) $jwtExecNeeded }}
{{- if not .Values.externalServer }} {{- if not .Values.externalServer }}
apiVersion: apps/v1 apiVersion: apps/v1
{{- if eq .Values.kind "statefulset" }} {{- if eq .Values.kind "statefulset" }}
@@ -86,6 +100,14 @@ spec:
{{- end }} {{- end }}
replicas: {{ .Values.replicaCount }} replicas: {{ .Values.replicaCount }}
{{- end }} {{- end }}
{{- with .Values.updateStrategy }}
{{- if eq $.Values.kind "statefulset" }}
updateStrategy:
{{- else }}
strategy:
{{- end }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if eq .Values.kind "statefulset" }} {{- if eq .Values.kind "statefulset" }}
serviceName: {{ include "spire-server.fullname" . }} serviceName: {{ include "spire-server.fullname" . }}
{{- end }} {{- end }}
@@ -176,6 +198,23 @@ spec:
mountPath: /plugins mountPath: /plugins
imagePullPolicy: {{ .Values.credentialComposer.spireIdentityExchange.image.pullPolicy }} imagePullPolicy: {{ .Values.credentialComposer.spireIdentityExchange.image.pullPolicy }}
{{- end }} {{- end }}
{{- if $jwtExecNeeded }}
- name: init-jwt-svid-exec
securityContext:
{{- include "spire-lib.securitycontext" . | nindent 12 }}
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.jwtSVIDExecConfig.image "global" .Values.global) }}
# Use the previously copied busybox to stage the exec credential plugin binary where the kubeConfigs consumers can fork it.
command:
- /plugins/busybox
- sh
- -ec
- |
/plugins/busybox cp -a {{ .Values.jwtSVIDExecConfig.pluginPath }} {{ include "spire-server.jwt-svid-exec-binary-path" . }}
volumeMounts:
- name: plugins
mountPath: /plugins
imagePullPolicy: {{ .Values.jwtSVIDExecConfig.image.pullPolicy }}
{{- end }}
{{- range $idx, $plugin := $pluginsToLoad }} {{- range $idx, $plugin := $pluginsToLoad }}
- name: {{ printf "init-plugin-%d" $idx }} - name: {{ printf "init-plugin-%d" $idx }}
securityContext: securityContext:
@@ -281,7 +320,9 @@ spec:
{{- with .Values.extraEnv }} {{- with .Values.extraEnv }}
{{- . | toYaml | nindent 10 }} {{- . | toYaml | nindent 10 }}
{{- end }} {{- end }}
{{- if and (ne .Values.dataStore.sql.databaseType "sqlite3") (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") }} {{- $postgresPasswordless := eq (include "spire-server.datastore-postgres-passwordless" .) "true" }}
{{- $postgresRoPasswordless := eq (include "spire-server.datastore-postgres-ro-passwordless" .) "true" }}
{{- if and (ne .Values.dataStore.sql.databaseType "sqlite3") (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") (not $postgresPasswordless) }}
{{- if .Values.dataStore.sql.externalSecret.enabled }} {{- if .Values.dataStore.sql.externalSecret.enabled }}
- name: DBPW - name: DBPW
valueFrom: valueFrom:
@@ -295,7 +336,8 @@ spec:
name: {{ $fullname }}-dbpw name: {{ $fullname }}-dbpw
key: DBPW key: DBPW
{{- end }} {{- end }}
{{- if and .Values.dataStore.sql.readOnly.enabled (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") }} {{- end }}
{{- if and .Values.dataStore.sql.readOnly.enabled (ne .Values.dataStore.sql.databaseType "gcp_mysql_sa_iam") (not $postgresRoPasswordless) }}
{{- if .Values.dataStore.sql.readOnly.externalSecret.enabled }} {{- if .Values.dataStore.sql.readOnly.externalSecret.enabled }}
- name: RODBPW - name: RODBPW
valueFrom: valueFrom:
@@ -310,7 +352,6 @@ spec:
key: RODBPW key: RODBPW
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }}
{{- if ne .Values.keyManager.awsKMS.accessKeyID "" }} {{- if ne .Values.keyManager.awsKMS.accessKeyID "" }}
- name: AWS_KMS_ACCESS_KEY_ID - name: AWS_KMS_ACCESS_KEY_ID
valueFrom: valueFrom:
@@ -408,6 +449,14 @@ spec:
mountPath: /tmp-direct-hashes mountPath: /tmp-direct-hashes
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if and .Values.nodeAttestor.x509POP.enabled (eq .Values.nodeAttestor.x509POP.mode "externalPKI") }}
{{- with .Values.nodeAttestor.x509POP }}
- name: x509pop-ca-bundle
mountPath: /run/spire/data/x509pop-ca-bundle.pem
subPath: ca-bundle.pem
readOnly: true
{{- end }}
{{- end }}
{{- if or .Values.federation.tls.certManager.enabled .Values.federation.tls.externalSecret.enabled }} {{- if or .Values.federation.tls.certManager.enabled .Values.federation.tls.externalSecret.enabled }}
- name: bundle-endpoint-tls - name: bundle-endpoint-tls
mountPath: /bundle-endpoint-tls mountPath: /bundle-endpoint-tls
@@ -646,6 +695,17 @@ spec:
name: {{ include "spire-server.fullname" . }}-tpm-direct-hash name: {{ include "spire-server.fullname" . }}-tpm-direct-hash
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if and .Values.nodeAttestor.x509POP.enabled (eq .Values.nodeAttestor.x509POP.mode "externalPKI") }}
{{- with .Values.nodeAttestor.x509POP }}
- name: x509pop-ca-bundle
configMap:
{{- if .caBundle.bundle }}
name: {{ $fullname }}-x509pop-ca
{{- else if .caBundle.existingConfigMap }}
name: {{ .caBundle.existingConfigMap }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.federation.tls.certManager.enabled }} {{- if .Values.federation.tls.certManager.enabled }}
- name: bundle-endpoint-tls - name: bundle-endpoint-tls
secret: secret:
@@ -15,6 +15,9 @@ spec:
{{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }} loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }} {{- end }}
{{- if and (eq .Values.service.type "LoadBalancer") .Values.service.externalTrafficPolicy }}
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
{{- end }}
ports: ports:
- name: grpc - name: grpc
port: {{ .Values.service.port }} port: {{ .Values.service.port }}
@@ -0,0 +1,10 @@
{{- if and .Values.nodeAttestor.x509POP.enabled .Values.nodeAttestor.x509POP.caBundle.bundle }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "spire-server.fullname" . }}-x509pop-ca
namespace: {{ include "spire-server.namespace" . }}
data:
ca-bundle.pem: |
{{ .Values.nodeAttestor.x509POP.caBundle.bundle | nindent 4 }}
{{- end }}
+81 -9
View File
@@ -23,9 +23,20 @@ image:
## @param kind Define SPIRE server deployment type. Can be statefulset/deployment. Defaults to statefulset if not set. This feature is experimental. ## @param kind Define SPIRE server deployment type. Can be statefulset/deployment. Defaults to statefulset if not set. This feature is experimental.
kind: statefulset kind: statefulset
## @param updateStrategy [object] Rollout strategy for the server, mapped to spec.updateStrategy when kind is "statefulset" and to spec.strategy when kind is "deployment". Left empty the Kubernetes default applies, which for a Deployment surges a second server before the old one goes away. Set `{type: Recreate}` to keep at most one server running, as a memory keyManager or an in-memory datastore requires.
updateStrategy: {}
## @param externalServer Deploy only the bundle ConfigMap, RBAC rules, and identity documents but not the server. Use in a nested setup where the server is external. ## @param externalServer Deploy only the bundle ConfigMap, RBAC rules, and identity documents but not the server. Use in a nested setup where the server is external.
externalServer: false externalServer: false
## @param externalServerSubject.kind RBAC subject kind the external (nested) server's downstream bindings are granted to. One of "User" (client-certificate identity, the historical default), "Group", or "ServiceAccount" (e.g. for a static-token kubeconfig). Only used when externalServer is true.
## @param externalServerSubject.name Name of the subject. For kind "User" it must match the CN of the client certificate the external server presents; for kind "Group" it is the group name (e.g. a certificate O value); for kind "ServiceAccount" it is the name of the (operator-managed, out-of-band) ServiceAccount.
## @param externalServerSubject.namespace Namespace of the ServiceAccount. Only used when kind is "ServiceAccount"; empty uses the server namespace.
externalServerSubject:
kind: User
name: spire-root
namespace: ""
## @param imagePullSecrets [array] Pull secrets for images ## @param imagePullSecrets [array] Pull secrets for images
imagePullSecrets: [] imagePullSecrets: []
@@ -82,6 +93,8 @@ service:
annotations: {} annotations: {}
## @param service.loadBalancerIP IP address to assign to load balancer (if supported) ## @param service.loadBalancerIP IP address to assign to load balancer (if supported)
loadBalancerIP: "" loadBalancerIP: ""
## @param service.externalTrafficPolicy Traffic policy applied when service.type is LoadBalancer (e.g. "Local" to preserve client source IP). Defaults to "Cluster" when left empty.
externalTrafficPolicy: ""
configMap: configMap:
## @param configMap.annotations [object] Annotations to add to the SPIRE Server ConfigMap ## @param configMap.annotations [object] Annotations to add to the SPIRE Server ConfigMap
@@ -114,6 +127,15 @@ autoscaling:
targetCPUUtilizationPercentage: 80 targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80
## @param podDisruptionBudget.enabled Flag to enable a PodDisruptionBudget for the SPIRE server pods
## @param podDisruptionBudget.minAvailable Minimum number/percentage of pods that must remain available (mutually exclusive with maxUnavailable)
## @param podDisruptionBudget.maxUnavailable Maximum number/percentage of pods that can be unavailable (mutually exclusive with minAvailable)
##
podDisruptionBudget:
enabled: false
minAvailable: ""
maxUnavailable: ""
## @param nodeSelector [object] Select specific nodes to run on (currently only amd64 is supported by Tornjak) ## @param nodeSelector [object] Select specific nodes to run on (currently only amd64 is supported by Tornjak)
nodeSelector: {} nodeSelector: {}
@@ -172,18 +194,20 @@ dataStore:
port: 0 port: 0
## @param dataStore.sql.username Only used when type != "sqlite3" ## @param dataStore.sql.username Only used when type != "sqlite3"
username: spire username: spire
## @param dataStore.sql.password Only used when type != "sqlite3" ## @param dataStore.sql.password Only used when type != "sqlite3". For postgres/aws_postgres, leave empty to omit the password from the connection string (e.g. TLS client-certificate or IAM authentication).
password: "" password: ""
## @param dataStore.sql.file Data source file. Only used when type == "sqlite3" ## @param dataStore.sql.file Data source file. Only used when type == "sqlite3" and inMemory is false
file: "/run/spire/data/datastore.sqlite3" file: "/run/spire/data/datastore.sqlite3"
## @param dataStore.sql.inMemory Hold the sqlite3 datastore in memory instead of in a file, in which case `file` is unused. The datastore starts empty on every restart, so this only suits a single replica whose registration entries are recreated at startup, for example by the controller manager writing static entries. Required to run as a deployment on sqlite3, since a deployment has no durable per-pod storage.
inMemory: false
## @param dataStore.sql.options [array] takes an array of objects of form {<key>: <value>} to use when building the database connection string ## @param dataStore.sql.options [array] takes an array of objects of form {<key>: <value>} to use when building the database connection string
options: [] options: []
## @param dataStore.sql.rootCAPath Path to Root CA bundle (MySQL only) ## @param dataStore.sql.rootCAPath Path to Root CA bundle. Supports MySQL and postgres.
rootCAPath: "" rootCAPath: ""
## @param dataStore.sql.clientCertPath Path to client certificate (MySQL only) ## @param dataStore.sql.clientCertPath Path to client certificate. Supports MySQL and postgres.
clientCertPath: "" clientCertPath: ""
## @param dataStore.sql.clientKeyPath Path to private key for client certificate (MySQL only) ## @param dataStore.sql.clientKeyPath Path to private key for client certificate. Supports MySQL and postgres.
clientKeyPath: "" clientKeyPath: ""
## When an external source creates the secret. The secret should reside in the same namespace as the spire server ## When an external source creates the secret. The secret should reside in the same namespace as the spire server
@@ -527,6 +551,19 @@ upstreamAuthority:
bundleFileArn: "" bundleFileArn: ""
## @param upstreamAuthority.awsSecret.assumeRoleArn (Optional) ARN of an IAM role to assume ## @param upstreamAuthority.awsSecret.assumeRoleArn (Optional) ARN of an IAM role to assume
assumeRoleArn: "" assumeRoleArn: ""
gcpCAS:
## @param upstreamAuthority.gcpCAS.enabled Flag to enable upstream authority plugin with GCP Certificate Authority Service
enabled: false
## @param upstreamAuthority.gcpCAS.projectName GCP project containing the root CA certificate
projectName: ""
## @param upstreamAuthority.gcpCAS.regionName GCP region name (e.g., us-central1)
regionName: ""
## @param upstreamAuthority.gcpCAS.caPool Name of the CA Pool that has the root CA certificate
caPool: ""
## @param upstreamAuthority.gcpCAS.labelKey Label key used to filter and select the relevant CA certificate
labelKey: ""
## @param upstreamAuthority.gcpCAS.labelValue Label value used to filter and select the relevant CA certificate
labelValue: ""
certManager: certManager:
## @param upstreamAuthority.certManager.enabled Flag to enable upstream authority plugin with cert manager ## @param upstreamAuthority.certManager.enabled Flag to enable upstream authority plugin with cert manager
enabled: false enabled: false
@@ -638,6 +675,8 @@ controllerManager:
className: "" className: ""
## @param controllerManager.watchClassless specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. ## @param controllerManager.watchClassless specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true.
watchClassless: false watchClassless: false
## @param controllerManager.filterByClassName Restrict the ClusterSPIFFEID cache to this controller's className. Only enable after confirming target ClusterSPIFFEIDs already carry the className label, or existing registrations will be deleted.
filterByClassName: false
## @param controllerManager.entryIDPrefixCleanup Sets which entry prefixes to remove for migrations. Consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. ## @param controllerManager.entryIDPrefixCleanup Sets which entry prefixes to remove for migrations. Consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it.
entryIDPrefixCleanup: false entryIDPrefixCleanup: false
@@ -950,6 +989,8 @@ externalControllerManagers:
className: "" className: ""
## @param externalControllerManagers.defaults.watchClassless specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true. ## @param externalControllerManagers.defaults.watchClassless specify to process custom resources without class name specified. Useful to slowly migrate to class names from classless installs. Do not have two installs on the same k8s cluster both set to true.
watchClassless: false watchClassless: false
## @param externalControllerManagers.defaults.filterByClassName Restrict the ClusterSPIFFEID cache to this controller's className. Only enable after confirming target ClusterSPIFFEIDs already carry the className label, or existing registrations will be deleted.
filterByClassName: false
## @param externalControllerManagers.defaults.entryIDPrefixCleanup consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it. ## @param externalControllerManagers.defaults.entryIDPrefixCleanup consult the spiffe.io docs about this option before changing. Its unlikely you will need to ever change it.
entryIDPrefixCleanup: false entryIDPrefixCleanup: false
## @param externalControllerManagers.defaults.parentIDTemplate The template that is used to register workloads. ## @param externalControllerManagers.defaults.parentIDTemplate The template that is used to register workloads.
@@ -1225,8 +1266,14 @@ nodeAttestor:
x509POP: x509POP:
## @param nodeAttestor.x509POP.enabled Enable the x509_popg node attestor ## @param nodeAttestor.x509POP.enabled Enable the x509_popg node attestor
enabled: false enabled: false
## @param nodeAttestor.x509POP.mode What mode to set the plugin to. Currently only spiffe mode is supported ## @param nodeAttestor.x509POP.mode Plugin mode: spiffe (exchange) or externalPKI (enrollment CA bundle)
mode: spiffe mode: spiffe
## @extra nodeAttestor.x509POP.caBundle CA bundle for externalPKI mode. Provide inline PEM contents or reference an existing ConfigMap.
caBundle:
## @param nodeAttestor.x509POP.caBundle.bundle [nullable] PEM CA bundle contents. When set, the chart creates and mounts a ConfigMap.
bundle: ""
## @param nodeAttestor.x509POP.caBundle.existingConfigMap [nullable] Name of a ConfigMap containing a `ca-bundle.pem` key with the PEM CA bundle.
existingConfigMap: ""
## @param nodeAttestor.x509POP.spiffePrefix What prefix to use when mode is spiffe ## @param nodeAttestor.x509POP.spiffePrefix What prefix to use when mode is spiffe
spiffePrefix: "/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/" spiffePrefix: "/spire-exchange/k8s${HELM_ADD_CLUSTER_NAME}/"
## @param nodeAttestor.x509POP.agentPathTemplate Override the default agent path template ## @param nodeAttestor.x509POP.agentPathTemplate Override the default agent path template
@@ -1593,9 +1640,11 @@ tests:
tag: latest@sha256:90041f375e30f41aa7e0390075d8a69dc61900771d52fa98d63ee5d03d866a58 tag: latest@sha256:90041f375e30f41aa7e0390075d8a69dc61900771d52fa98d63ee5d03d866a58
## @param kubeConfigs [object] Manage additional kubeconfig files to talk to external Kubernetes clusters ## @param kubeConfigs [object] Manage additional kubeconfig files to talk to external Kubernetes clusters
## Each entry sets exactly one of kubeConfig, kubeConfigBase64, or externalSecret. Use externalSecret to ## Each entry sets exactly one of kubeConfig, kubeConfigBase64, externalSecret, or jwtSVIDExec. Use externalSecret
## reference a kubeconfig from an externally-managed Secret instead of embedding it in values; ## to reference a kubeconfig from an externally-managed Secret instead of embedding it in values; entries may
## entries may reference different Secrets and mix with inline ones. ## reference different Secrets and mix with inline ones. Use jwtSVIDExec to have the chart generate an
## exec-credential kubeconfig that authenticates to the target cluster with short-lived SPIFFE JWT-SVIDs fetched
## at call time by the exec plugin (see jwtSVIDExecConfig).
kubeConfigs: {} kubeConfigs: {}
# clustera: # clustera:
# kubeConfig: | # kubeConfig: |
@@ -1607,6 +1656,29 @@ kubeConfigs: {}
# externalSecret: # externalSecret:
# name: my-kubeconfigs-secret # name of the externally-managed Secret to read from # name: my-kubeconfigs-secret # name of the externally-managed Secret to read from
# key: clusterc # optional, defaults to the entry name # key: clusterc # optional, defaults to the entry name
# clusterd:
# jwtSVIDExec:
# server: https://clusterd-api.example.com:6443 # target apiserver URL
# certificateAuthorityData: LS0tLS1CRUdJ... # apiserver CA bundle, base64-encoded PEM (kubeconfig certificate-authority-data)
# audience: k8s # optional, JWT-SVID audience the target expects (default k8s)
## @param jwtSVIDExecConfig.image.registry The OCI registry to pull the exec credential plugin image from
## @param jwtSVIDExecConfig.image.repository The repository within the registry
## @param jwtSVIDExecConfig.image.pullPolicy The image pull policy
## @param jwtSVIDExecConfig.image.tag Overrides the image tag
## @param jwtSVIDExecConfig.pluginPath The path of the plugin binary inside the plugin image, staged for exec by the kubeConfigs consumers
## @param jwtSVIDExecConfig.spiffeID The SPIFFE ID the plugin mints a JWT-SVID for; a full spiffe:// URI, or a "/"-prefixed path expanded with the chart trust domain (e.g. /spire-root); required when any kubeConfigs entry uses jwtSVIDExec
## Global wiring shared by every kubeConfigs entry that uses jwtSVIDExec. The plugin binary is staged from this
## image into the shared plugins volume, and every such entry mints a JWT-SVID for spiffeID from the SPIRE Server
## admin API socket, which is already mounted into the kubeConfigs consumers, so no agent Workload API socket is required.
jwtSVIDExecConfig:
image:
registry: ghcr.io
repository: spiffe/k8s-spiffe-workload-jwt-exec-auth
pullPolicy: IfNotPresent
tag: "0.2.0"
pluginPath: /ko-app/cmd
spiffeID: "/spire-root"
spireIdentityExchange: spireIdentityExchange:
## @param spireIdentityExchange.enabled Enable the server side of the SPIRE Identity Exchange system ## @param spireIdentityExchange.enabled Enable the server side of the SPIRE Identity Exchange system
+18
View File
@@ -22,6 +22,24 @@ Warning: You're using an unsupported plugin. Functionality of this release and f
Warning: You're using an experimental config. Functionality of this release and future upgrades aren't guaranteed to work smoothly. Warning: You're using an experimental config. Functionality of this release and future upgrades aren't guaranteed to work smoothly.
{{- end }} {{- end }}
{{- if (index .Values "spire-server").enabled }} {{- if (index .Values "spire-server").enabled }}
{{- $ss := index .Values "spire-server" }}
{{- if and (eq $ss.dataStore.sql.databaseType "sqlite3") $ss.dataStore.sql.inMemory }}
{{- $upstream := false }}
{{- range $name, $cfg := $ss.upstreamAuthority }}
{{- if kindIs "map" $cfg }}{{ if eq ($cfg.enabled | toString) "true" }}{{ $upstream = true }}{{ end }}{{ end }}
{{- end }}
{{- $reconciled := and $ss.controllerManager.enabled (or $ss.controllerManager.reconcile.clusterSPIFFEIDs $ss.controllerManager.reconcile.clusterStaticEntries) }}
{{- if not $reconciled }}
Warning: dataStore.sql.inMemory is set, but no controller manager reconciler is enabled. Registration entries live only in memory and nothing recreates them, so every entry is lost when the server restarts. Enable controllerManager with reconcile.clusterSPIFFEIDs or reconcile.clusterStaticEntries.
{{- end }}
{{- if and $ss.keyManager.memory.enabled (not $upstream) }}
Warning: dataStore.sql.inMemory is set with keyManager.memory and no upstreamAuthority. The server mints a new CA on every restart, so the whole trust domain has to re-attest and previously issued SVIDs stop verifying. Suitable for testing only; configure a KMS key manager or an upstream authority for anything else.
{{- end }}
{{- end }}
{{- end }}
{{- if (index .Values "spire-server").enabled }}
{{- $className := include "spire-server.controller-manager-class-name" (dict "Values" (index .Values "spire-server") "Release" .Release) }} {{- $className := include "spire-server.controller-manager-class-name" (dict "Values" (index .Values "spire-server") "Release" .Release) }}
{{- if (index .Values "spire-server").controllerManager.enabled }} {{- if (index .Values "spire-server").controllerManager.enabled }}
{{- if (index .Values "spire-server").controllerManager.watchClassless }} {{- if (index .Values "spire-server").controllerManager.watchClassless }}
@@ -36,10 +36,10 @@ spec:
i=0 i=0
while [ "$i" -lt 60 ]; do while [ "$i" -lt 60 ]; do
if XOUT=$(/opt/spire/bin/spire-agent api fetch x509 -socketPath "$SOCK" -write /data -timeout 5s 2>&1) && if XOUT=$(/opt/spire/bin/spire-agent api fetch x509 -socketPath "$SOCK" -write /data -timeout 5s 2>&1) &&
echo "$XOUT" | /data/busybox grep -q "for trust domain other.org" && echo "$XOUT" | /data/busybox grep -q "for trust domain other.invalid" &&
JOUT=$(/opt/spire/bin/spire-agent api fetch jwt -audience test -socketPath "$SOCK" -timeout 5s 2>&1) && JOUT=$(/opt/spire/bin/spire-agent api fetch jwt -audience test -socketPath "$SOCK" -timeout 5s 2>&1) &&
echo "$JOUT" | /data/busybox grep -q "bundle(other.org)"; then echo "$JOUT" | /data/busybox grep -q "bundle(other.invalid)"; then
# The other.org bundle was statically set to the same single CA on both sides, # Both sides were seeded with the same single-CA other.invalid bundle at install,
# so every federated bundle delivered must contain exactly one certificate. # so every federated bundle delivered must contain exactly one certificate.
for f in /data/federated_bundle.*.pem; do for f in /data/federated_bundle.*.pem; do
COUNT=$(/data/busybox grep -c "BEGIN CERTIFICATE" "$f") COUNT=$(/data/busybox grep -c "BEGIN CERTIFICATE" "$f")
+48 -27
View File
@@ -31,8 +31,13 @@ done
# With -b, test the spire-ha-agent broker api instead of the delegated api. # With -b, test the spire-ha-agent broker api instead of the delegated api.
# Broker mode also supports federated trust bundles, so federate the ha-agent's own entry and a # Broker mode also supports federated trust bundles, so federate the ha-agent's own entry and a
# dedicated federation-test workload entry with the other.org trust domain on both sides. Delegated # dedicated federation-test workload entry with the other.invalid trust domain on both sides. Delegated
# mode only tolerates the local and spire-ha bundles, so none of this may apply without -b. # mode only tolerates the local and spire-ha bundles, so none of this may apply without -b.
# Placeholder bundle endpoint for other.invalid. Its ClusterFederatedTrustDomain carries the bundle
# verbatim, but the CRD requires an endpoint alongside it. This name is never meant to answer, it
# just has to be ours: .invalid can never be registered, and coredns pins it to 127.0.0.1 below.
FEDERATION_ENDPOINT_HOST=spire-server-federation.other.invalid
BROKER_MODE_ARGS=() BROKER_MODE_ARGS=()
BROKER_SOCKET_ARGS_A=() BROKER_SOCKET_ARGS_A=()
BROKER_SOCKET_ARGS_B=() BROKER_SOCKET_ARGS_B=()
@@ -41,15 +46,15 @@ if [ "${BROKER}" -eq 1 ]; then
BROKER_SOCKET_ARGS_A=( BROKER_SOCKET_ARGS_A=(
--set downstream-spire-agent-bottom-turtle-ha-a.sockets.broker.enabled=true --set downstream-spire-agent-bottom-turtle-ha-a.sockets.broker.enabled=true
--set downstream-spire-agent-bottom-turtle-ha-a.sockets.broker.mountOnHost=true --set downstream-spire-agent-bottom-turtle-ha-a.sockets.broker.mountOnHost=true
--set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.federatesWith={spire-ha,other.org}' --set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.federatesWith={spire-ha,other.invalid}'
--set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.federation-test.federatesWith={other.org}' --set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.federation-test.federatesWith={other.invalid}'
--set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.federation-test.podSelector.matchLabels.app=federation-test' --set 'internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterSPIFFEIDs.federation-test.podSelector.matchLabels.app=federation-test'
) )
BROKER_SOCKET_ARGS_B=( BROKER_SOCKET_ARGS_B=(
--set downstream-spire-agent-bottom-turtle-ha-b.sockets.broker.enabled=true --set downstream-spire-agent-bottom-turtle-ha-b.sockets.broker.enabled=true
--set downstream-spire-agent-bottom-turtle-ha-b.sockets.broker.mountOnHost=true --set downstream-spire-agent-bottom-turtle-ha-b.sockets.broker.mountOnHost=true
--set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.federatesWith={spire-ha,other.org}' --set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.spire-ha-agent.federatesWith={spire-ha,other.invalid}'
--set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.federation-test.federatesWith={other.org}' --set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.federation-test.federatesWith={other.invalid}'
--set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.federation-test.podSelector.matchLabels.app=federation-test' --set 'internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterSPIFFEIDs.federation-test.podSelector.matchLabels.app=federation-test'
) )
fi fi
@@ -95,6 +100,7 @@ teardown() {
kubectl describe daemonset pods -n spire-system || true kubectl describe daemonset pods -n spire-system || true
kubectl get configmap -n spire-system || true kubectl get configmap -n spire-system || true
kubectl get configmap -n spire-system spire-a-agent-downstream -o yaml || true kubectl get configmap -n spire-system spire-a-agent-downstream -o yaml || true
kubectl get endpoints -n spire-server -o yaml || true
print_helm_releases print_helm_releases
@@ -204,17 +210,38 @@ if [ "${BROKER}" -eq 1 ]; then
BUSYBOX_IMAGE=$(helm template t charts/spire -s charts/spiffe-oidc-discovery-provider/templates/tests/test-keys.yaml --values "${COMMON_TEST_YOUR_VALUES}" --set spiffe-oidc-discovery-provider.enabled=true | yq e 'select(.kind=="Pod") | .spec.initContainers[] | select(.name=="static-busybox") | .image' -) BUSYBOX_IMAGE=$(helm template t charts/spire -s charts/spiffe-oidc-discovery-provider/templates/tests/test-keys.yaml --values "${COMMON_TEST_YOUR_VALUES}" --set spiffe-oidc-discovery-provider.enabled=true | yq e 'select(.kind=="Pod") | .spec.initContainers[] | select(.name=="static-busybox") | .image' -)
echo "federation test job images: ${AGENT_IMAGE} ${BUSYBOX_IMAGE}" echo "federation test job images: ${AGENT_IMAGE} ${BUSYBOX_IMAGE}"
# Mint a trust bundle for a foreign trust domain (other.org) to test federated trust bundle # Mint a trust bundle for a foreign trust domain (other.invalid) to test federated trust bundle
# support. A throwaway third spire-server instance produces a genuine spiffe format bundle # support. A throwaway third spire-server instance produces a genuine spiffe format bundle
# carrying both x509 and jwt authorities. The instance env file overrides the global trust # carrying both x509 and jwt authorities. The instance env file overrides the global trust
# domain since systemd applies later EnvironmentFiles last. # domain since systemd applies later EnvironmentFiles last.
sudo /bin/bash -c '(echo SPIFFE_TRUST_DOMAIN=other.org; echo SPIRE_BIND_PORT=8083) > /etc/spire/server/other.env' sudo /bin/bash -c '(echo SPIFFE_TRUST_DOMAIN=other.invalid; echo SPIRE_BIND_PORT=8083) > /etc/spire/server/other.env'
sudo systemctl start spire-server@other sudo systemctl start spire-server@other
wait_for_healthcheck spire-server /run/spire/server/sockets/other/private/api.sock wait_for_healthcheck spire-server /run/spire/server/sockets/other/private/api.sock
sudo spire-server bundle show -format spiffe -socketPath /run/spire/server/sockets/other/private/api.sock | sudo tee /tmp/other-org-bundle.json > /dev/null sudo spire-server bundle show -format spiffe -socketPath /run/spire/server/sockets/other/private/api.sock | sudo tee /tmp/other-invalid-bundle.json > /dev/null
sudo systemctl stop spire-server@other sudo systemctl stop spire-server@other
grep -q '"x509-svid"' /tmp/other-org-bundle.json grep -q '"x509-svid"' /tmp/other-invalid-bundle.json
grep -q '"jwt-svid"' /tmp/other-org-bundle.json grep -q '"jwt-svid"' /tmp/other-invalid-bundle.json
# Seed the bundle into each server's ClusterFederatedTrustDomain so the controller manager can
# create the entries that federate with other.invalid on its first reconcile. Loading it after
# the install instead leaves the ha-agent without an SVID for the whole helm --wait window.
# The CRD requires an endpoint even when the bundle is supplied verbatim; .invalid can never be
# registered and coredns pins the name locally, so the endpoint never answers. That is fine,
# spire keeps a federated bundle when a refresh fails.
FTD_A=internal-spire-server-bottom-turtle-ha-a.controllerManager.identities.clusterFederatedTrustDomains.other
FTD_B=internal-spire-server-bottom-turtle-ha-b.controllerManager.identities.clusterFederatedTrustDomains.other
BROKER_SOCKET_ARGS_A+=(
--set "${FTD_A}.trustDomain=other.invalid"
--set "${FTD_A}.bundleEndpointProfile.type=https_web"
--set "${FTD_A}.bundleEndpointURL=https://${FEDERATION_ENDPOINT_HOST}"
--set-file "${FTD_A}.trustDomainBundle=/tmp/other-invalid-bundle.json"
)
BROKER_SOCKET_ARGS_B+=(
--set "${FTD_B}.trustDomain=other.invalid"
--set "${FTD_B}.bundleEndpointProfile.type=https_web"
--set "${FTD_B}.bundleEndpointURL=https://${FEDERATION_ENDPOINT_HOST}"
--set-file "${FTD_B}.trustDomainBundle=/tmp/other-invalid-bundle.json"
)
fi fi
# register some workloads with the spire server using manifests # register some workloads with the spire server using manifests
@@ -305,7 +332,7 @@ common_test_url "$IP"
# Get the host IP And add spire-server-[ab].${trust_domain} records to it so the spire-servers can talk back to root servers running on the host # Get the host IP And add spire-server-[ab].${trust_domain} records to it so the spire-servers can talk back to root servers running on the host
HOSTIP=$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) HOSTIP=$(ip addr show docker0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
kubectl get configmap -n kube-system coredns -o yaml | grep hosts || kubectl get configmap -n kube-system coredns -o yaml | sed "/ready/a\ hosts {\n fallthrough\n }" | kubectl apply -f - kubectl get configmap -n kube-system coredns -o yaml | grep hosts || kubectl get configmap -n kube-system coredns -o yaml | sed "/ready/a\ hosts {\n fallthrough\n }" | kubectl apply -f -
kubectl get configmap -n kube-system coredns -o yaml | grep production.other || kubectl get configmap -n kube-system coredns -o yaml | sed "/hosts/a\ $HOSTIP spire-server-a.production.other\n $HOSTIP oidc-discovery.production.other\n $HOSTIP spire-server-b.production.other\n" | kubectl apply -f - kubectl get configmap -n kube-system coredns -o yaml | grep production.other || kubectl get configmap -n kube-system coredns -o yaml | sed "/hosts/a\ $HOSTIP spire-server-a.production.other\n $IP oidc-discovery.production.other\n $HOSTIP spire-server-b.production.other\n 127.0.0.1 $FEDERATION_ENDPOINT_HOST\n" | kubectl apply -f -
kubectl rollout restart -n kube-system deployment/coredns kubectl rollout restart -n kube-system deployment/coredns
kubectl rollout status -n kube-system -w --timeout=1m deploy/coredns kubectl rollout status -n kube-system -w --timeout=1m deploy/coredns
@@ -330,19 +357,13 @@ kubectl create secret tls -n spire-server spire-identity-exchange --key=certs/se
# Install server side a # Install server side a
helm upgrade --install --namespace spire-mgmt --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/spire-values.yaml" \ helm upgrade --install --namespace spire-mgmt --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/spire-values.yaml" \
--wait spire-a charts/spire-nested \ --wait --timeout 7m spire-a charts/spire-nested \
--set tags.bottomTurtleHAA=true \ --set tags.bottomTurtleHAA=true \
--values "${SCRIPTPATH}/spire-identity-exchange-values.yaml" \ --values "${SCRIPTPATH}/spire-identity-exchange-values.yaml" \
--set "spire-identity-exchange-bottom-turtle-ha-a.enabled=true" \ --set "spire-identity-exchange-bottom-turtle-ha-a.enabled=true" \
--set "global.spire.ingressControllerType=ingress-nginx" \ --set "global.spire.ingressControllerType=ingress-nginx" \
"${BROKER_SOCKET_ARGS_A[@]}" "${BROKER_SOCKET_ARGS_A[@]}"
if [ "${BROKER}" -eq 1 ]; then
# Install the other.org bundle so the controller manager can create the entries that federate
# with it. It retries any entries that failed with "unable to find federated bundle".
kubectl exec -i -n spire-server spire-a-internal-server-0 -- spire-server bundle set -format spiffe -id spiffe://other.org < /tmp/other-org-bundle.json
fi
docker exec -i chart-testing-worker /bin/bash -c "more /var/lib/kubelet/pods/*/volumes/kubernetes.io~empty-dir/disk-keymanager/keys.json /var/lib/kubelet/pods/*/volumes/kubernetes.io~empty-dir/spire-agent-persistence/agent-data.json | cat" docker exec -i chart-testing-worker /bin/bash -c "more /var/lib/kubelet/pods/*/volumes/kubernetes.io~empty-dir/disk-keymanager/keys.json /var/lib/kubelet/pods/*/volumes/kubernetes.io~empty-dir/spire-agent-persistence/agent-data.json | cat"
# Rollout just to sped up the tests # Rollout just to sped up the tests
@@ -356,7 +377,7 @@ curl -k --resolve "oidc-discovery.production.other:443:$IP" "https://oidc-discov
# Install server side b # Install server side b
helm upgrade --install --namespace spire-mgmt --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/spire-values.yaml" \ helm upgrade --install --namespace spire-mgmt --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/spire-values.yaml" \
--wait spire-b charts/spire-nested \ --wait --timeout 7m spire-b charts/spire-nested \
--set tags.bottomTurtleHAB=true \ --set tags.bottomTurtleHAB=true \
--set internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.port=8082 \ --set internal-spire-server-bottom-turtle-ha-b.upstreamAuthority.spire.server.port=8082 \
--values "${SCRIPTPATH}/spire-identity-exchange-values.yaml" \ --values "${SCRIPTPATH}/spire-identity-exchange-values.yaml" \
@@ -365,10 +386,10 @@ helm upgrade --install --namespace spire-mgmt --values "${COMMON_TEST_YOUR_VALUE
"${BROKER_SOCKET_ARGS_B[@]}" "${BROKER_SOCKET_ARGS_B[@]}"
if [ "${BROKER}" -eq 1 ]; then if [ "${BROKER}" -eq 1 ]; then
kubectl exec -i -n spire-server spire-b-internal-server-0 -- spire-server bundle set -format spiffe -id spiffe://other.org < /tmp/other-org-bundle.json # Both sides' spire-ha-agent entries must federate with other.invalid before the workload test.
# Both sides' spire-ha-agent entries must federate with other.org before the workload test. # The bundle came in with the install, so this should already be true rather than waited on.
wait_for_entry_federation spire-a-internal-server-0 other.org wait_for_entry_federation spire-a-internal-server-0 other.invalid
wait_for_entry_federation spire-b-internal-server-0 other.org wait_for_entry_federation spire-b-internal-server-0 other.invalid
fi fi
docker ps docker ps
@@ -398,11 +419,11 @@ curl -k --resolve "oidc-discovery.production.other:443:$IP" "https://oidc-discov
kubectl apply -f "${SCRIPTPATH}/test-job.yaml" kubectl apply -f "${SCRIPTPATH}/test-job.yaml"
kubectl wait --for=condition=complete --timeout=60s job/test && \ kubectl wait --for=condition=complete --timeout=60s job/test && \
TOKEN=$(kubectl logs job/test) TOKEN=$(kubectl logs job/test)
curl -f -H "Authorization: Bearer ${TOKEN}" -X POST --resolve "spire-identity-exchange-a-rest.production.other:443:$IP" "https://spire-identity-exchange-a-rest.production.other/api/v1/svid/k8s_psat/x509" -k -sS -q curl --fail-with-body -H "Authorization: Bearer ${TOKEN}" -X POST --resolve "spire-identity-exchange-a-rest.production.other:443:$IP" "https://spire-identity-exchange-a-rest.production.other/api/v1/svid/k8s_psat/x509" -k -sS -q
curl -f -H "Authorization: Bearer ${TOKEN}" -X POST --resolve "spire-identity-exchange-b-rest.production.other:443:$IP" "https://spire-identity-exchange-b-rest.production.other/api/v1/svid/k8s_psat/x509" -k -sS -q curl --fail-with-body -H "Authorization: Bearer ${TOKEN}" -X POST --resolve "spire-identity-exchange-b-rest.production.other:443:$IP" "https://spire-identity-exchange-b-rest.production.other/api/v1/svid/k8s_psat/x509" -k -sS -q
if [ "${BROKER}" -eq 1 ]; then if [ "${BROKER}" -eq 1 ]; then
# Verify a workload on the ha-agent socket receives the other.org federated trust bundles, # Verify a workload on the ha-agent socket receives the other.invalid federated trust bundles,
# x509 and jwt, merged from both sides. # x509 and jwt, merged from both sides.
run_federation_test_job run_federation_test_job
fi fi
@@ -416,7 +437,7 @@ kubectl rollout status deployment -n spire-server spiffe-oidc-discovery-provider
curl -k --resolve "oidc-discovery.production.other:443:$IP" "https://oidc-discovery.production.other/.well-known/openid-configuration" -s --fail curl -k --resolve "oidc-discovery.production.other:443:$IP" "https://oidc-discovery.production.other/.well-known/openid-configuration" -s --fail
if [ "${BROKER}" -eq 1 ]; then if [ "${BROKER}" -eq 1 ]; then
# Verify the other.org federated trust bundles still serve with only side b running. # Verify the other.invalid federated trust bundles still serve with only side b running.
run_federation_test_job run_federation_test_job
fi fi
@@ -1,4 +1,4 @@
internal-spire-server-bottom-turtle-ha-a: internal-spire-server-bottom-turtle-ha-a: &server
controllerManager: controllerManager:
identities: identities:
clusterStaticEntries: clusterStaticEntries:
@@ -11,49 +11,25 @@ internal-spire-server-bottom-turtle-ha-a:
spireIdentityExchange: spireIdentityExchange:
enabled: true enabled: true
internal-spire-server-bottom-turtle-ha-b: #Set the same settings on the B side
controllerManager: internal-spire-server-bottom-turtle-ha-b: *server
identities:
clusterStaticEntries:
test:
parentID: spiffe://production.other/spire-identity-exchange
spiffeID: spiffe://production.other/k8s-psat/test
selectors:
- k8s_psat:namespace:default
- k8s_psat:service_account_name:default
spireIdentityExchange:
enabled: true
spire-identity-exchange-bottom-turtle-ha-a: spire-identity-exchange-bottom-turtle-ha-a: &six
rest:
ingress:
enabled: true
tls: tls:
externalSecret: externalSecret:
enabled: true enabled: true
secretName: spire-identity-exchange secretName: spire-identity-exchange
rest:
enabled: true
ingress:
enabled: true
auth: auth:
passthroughPlugins: true
plugins: plugins:
- plugin: k8s_psat k8s_psat:
config: config:
audiences:
- spire-identity-exchange
allowedServiceAccounts: allowedServiceAccounts:
- default/default - default/default
spire-identity-exchange-bottom-turtle-ha-b: #Set the same settings on the B side
rest: spire-identity-exchange-bottom-turtle-ha-b: *six
ingress:
enabled: true
tls:
externalSecret:
enabled: true
secretName: spire-identity-exchange
auth:
plugins:
- plugin: k8s_psat
config:
audiences:
- spire-identity-exchange
allowedServiceAccounts:
- default/default
+10 -10
View File
@@ -3,9 +3,9 @@ module github.com/spiffe/helm-charts/tests
go 1.26.0 go 1.26.0
require ( require (
github.com/onsi/ginkgo/v2 v2.32.0 github.com/onsi/ginkgo/v2 v2.32.1
github.com/onsi/gomega v1.42.1 github.com/onsi/gomega v1.42.1
helm.sh/helm/v3 v3.21.3 helm.sh/helm/v3 v3.21.4
) )
require ( require (
@@ -44,16 +44,16 @@ require (
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.53.0 // indirect golang.org/x/crypto v0.54.0 // indirect
golang.org/x/mod v0.36.0 // indirect golang.org/x/mod v0.37.0 // indirect
golang.org/x/net v0.56.0 // indirect golang.org/x/net v0.56.0 // indirect
golang.org/x/oauth2 v0.35.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.21.0 // indirect golang.org/x/sync v0.22.0 // indirect
golang.org/x/sys v0.46.0 // indirect golang.org/x/sys v0.47.0 // indirect
golang.org/x/term v0.44.0 // indirect golang.org/x/term v0.45.0 // indirect
golang.org/x/text v0.38.0 // indirect golang.org/x/text v0.40.0 // indirect
golang.org/x/time v0.14.0 // indirect golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.45.0 // indirect golang.org/x/tools v0.47.0 // indirect
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
+20 -20
View File
@@ -89,8 +89,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.32.0 h1:Hw7s2pVrQo/8Yz5N77qdnpHaoc+c6cC9WIV1Jce+J6E= github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw=
github.com/onsi/ginkgo/v2 v2.32.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44= github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I= github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I=
github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg= github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -133,26 +133,26 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -165,8 +165,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
helm.sh/helm/v3 v3.21.3 h1:wkamdwI3liEkW6wI1l9aGqQZGxcTKyt8kx0qJLPcmCg= helm.sh/helm/v3 v3.21.4 h1:T/GcIEXU/gNjJnkITlIZ3e9xqkZjhFTmISuStTZ6+Qg=
helm.sh/helm/v3 v3.21.3/go.mod h1:iaJ0iNsPoTZl++7h6vzQFyT0VEVtLYJiyRBDkPOOBTs= helm.sh/helm/v3 v3.21.4/go.mod h1:cS2FBb+xfLuaSqvEmbqIeKUVFgHdHVHtVeXb2epof3M=
k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY=
k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg=
k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4= k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4=
+599
View File
@@ -1,6 +1,10 @@
package unit_test package unit_test
import ( import (
"encoding/json"
"io"
"strings"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -8,8 +12,71 @@ import (
helmloader "helm.sh/helm/v3/pkg/chart/loader" helmloader "helm.sh/helm/v3/pkg/chart/loader"
helmutil "helm.sh/helm/v3/pkg/chartutil" helmutil "helm.sh/helm/v3/pkg/chartutil"
helmengine "helm.sh/helm/v3/pkg/engine" helmengine "helm.sh/helm/v3/pkg/engine"
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
) )
type renderedWebhook struct {
Name string `json:"name"`
FailurePolicy string `json:"failurePolicy"`
}
type renderedDocument struct {
Kind string `json:"kind"`
Metadata struct {
Annotations map[string]string `json:"annotations"`
} `json:"metadata"`
Spec struct {
Template struct {
Spec struct {
Containers []struct {
Args []string `json:"args"`
} `json:"containers"`
} `json:"spec"`
} `json:"template"`
} `json:"spec"`
Webhooks []renderedWebhook `json:"webhooks"`
}
func decodeRenderedDocuments(rendered string) ([]renderedDocument, error) {
decoder := yamlutil.NewYAMLOrJSONDecoder(strings.NewReader(rendered), 4096)
var documents []renderedDocument
for {
var document renderedDocument
err := decoder.Decode(&document)
if err == io.EOF {
return documents, nil
}
if err != nil {
return nil, err
}
if document.Kind != "" {
documents = append(documents, document)
}
}
}
func patchWebhookNames(job renderedDocument) ([]string, error) {
for _, container := range job.Spec.Template.Spec.Containers {
for index, arg := range container.Args {
if arg != "-p" || index+1 >= len(container.Args) {
continue
}
var patch struct {
Webhooks []renderedWebhook `json:"webhooks"`
}
if err := json.Unmarshal([]byte(container.Args[index+1]), &patch); err != nil {
return nil, err
}
names := make([]string, 0, len(patch.Webhooks))
for _, webhook := range patch.Webhooks {
names = append(names, webhook.Name)
}
return names, nil
}
}
return nil, nil
}
func ValueStringRender(chart *helmchart.Chart, values string) (map[string]string, error) { func ValueStringRender(chart *helmchart.Chart, values string) (map[string]string, error) {
v, err := helmutil.ReadValues([]byte(values)) v, err := helmutil.ReadValues([]byte(values))
if err != nil { if err != nil {
@@ -187,6 +254,52 @@ spire-server:
Expect(notes).Should(ContainSubstring("Installed")) Expect(notes).Should(ContainSubstring("Installed"))
}) })
}) })
Describe("spire-server.nodeAttestor.x509POP", func() {
It("renders externalPKI mode with chart-managed ca bundle", func() {
objs, err := ValueStringRender(chart, `
spire-server:
nodeAttestor:
k8sPSAT:
enabled: false
x509POP:
enabled: true
mode: externalPKI
caBundle:
bundle: |
-----BEGIN CERTIFICATE-----
MIIB...
-----END CERTIFICATE-----
`)
Expect(err).Should(Succeed())
serverCM := objs["spire/charts/spire-server/templates/configmap.yaml"]
Expect(serverCM).Should(ContainSubstring(`"mode": "external_pki"`))
Expect(serverCM).Should(ContainSubstring(`"ca_bundle_path": "/run/spire/data/x509pop-ca-bundle.pem"`))
Expect(objs).Should(HaveKey("spire/charts/spire-server/templates/x509pop-configmap.yaml"))
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("x509pop-ca-bundle"))
Expect(serverResource).Should(ContainSubstring("/run/spire/data/x509pop-ca-bundle.pem"))
})
It("renders externalPKI mode with existing ConfigMap reference", func() {
objs, err := ValueStringRender(chart, `
spire-server:
nodeAttestor:
k8sPSAT:
enabled: false
x509POP:
enabled: true
mode: externalPKI
caBundle:
existingConfigMap: my-enrollment-ca
`)
Expect(err).Should(Succeed())
serverCM := objs["spire/charts/spire-server/templates/configmap.yaml"]
Expect(serverCM).Should(ContainSubstring(`"mode": "external_pki"`))
Expect(serverCM).Should(ContainSubstring(`"ca_bundle_path": "/run/spire/data/x509pop-ca-bundle.pem"`))
Expect(objs["spire/charts/spire-server/templates/x509pop-configmap.yaml"]).ShouldNot(ContainSubstring("kind: ConfigMap"))
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("name: my-enrollment-ca"))
})
})
Describe("spire-server.nodeAttestor.awsIID.verifyOrganization", func() { Describe("spire-server.nodeAttestor.awsIID.verifyOrganization", func() {
It("emits verify_organization in server config JSON", func() { It("emits verify_organization in server config JSON", func() {
objs, err := ValueStringRender(chart, ` objs, err := ValueStringRender(chart, `
@@ -287,5 +400,491 @@ spire-server:
Expect(objs[serverTmpl]).Should(ContainSubstring("name: my-ext-secret")) Expect(objs[serverTmpl]).Should(ContainSubstring("name: my-ext-secret"))
Expect(objs[serverTmpl]).Should(ContainSubstring("path: clusterb")) Expect(objs[serverTmpl]).Should(ContainSubstring("path: clusterb"))
}) })
It("jwtSVIDExec entry generates the Secret and stages the exec plugin", func() {
objs, err := ValueStringRender(chart, `
spire-server:
jwtSVIDExecConfig:
spiffeID: spiffe://example.org/external-spire-server
kubeConfigs:
clusterd:
jwtSVIDExec:
server: https://clusterd-api.example.com:6443
certificateAuthorityData: TESTCADATAB64==
`)
Expect(err).Should(Succeed())
Expect(objs[secretTmpl]).Should(ContainSubstring("kind: Secret"))
Expect(objs[serverTmpl]).Should(ContainSubstring("init-jwt-svid-exec"))
})
})
Describe("spiffe-csi-driver.syncWave", func() {
csiTmpl := "spire/charts/spiffe-csi-driver/templates/spiffe-csi-driver.yaml"
It("renders the default sync-wave annotation on OpenShift", func() {
objs, err := ValueStringRender(chart, `
global:
openshift: true
`)
Expect(err).Should(Succeed())
Expect(objs[csiTmpl]).Should(ContainSubstring(`argocd.argoproj.io/sync-wave: "-1"`))
})
It("allows overriding the sync-wave number", func() {
objs, err := ValueStringRender(chart, `
global:
openshift: true
spiffe-csi-driver:
syncWave: -2
`)
Expect(err).Should(Succeed())
Expect(objs[csiTmpl]).Should(ContainSubstring(`argocd.argoproj.io/sync-wave: "-2"`))
})
It("allows overriding the annotation via csiDriverAnnotations", func() {
objs, err := ValueStringRender(chart, `
global:
openshift: true
spiffe-csi-driver:
csiDriverAnnotations:
argocd.argoproj.io/sync-wave: "-5"
`)
Expect(err).Should(Succeed())
Expect(objs[csiTmpl]).Should(ContainSubstring(`argocd.argoproj.io/sync-wave: "-5"`))
})
It("does not render the sync-wave annotation when not on OpenShift", func() {
objs, err := ValueStringRender(chart, ``)
Expect(err).Should(Succeed())
Expect(objs[csiTmpl]).ShouldNot(ContainSubstring("argocd.argoproj.io/sync-wave"))
})
})
Describe("spire-server.externalServerSubject", func() {
It("binds the external server's downstream RBAC to a ServiceAccount subject", func() {
objs, err := ValueStringRender(chart, `
spire-server:
externalServer: true
externalServerSubject:
kind: ServiceAccount
name: spire-external
namespace: spire-ext
`)
Expect(err).Should(Succeed())
roles := objs["spire/charts/spire-server/templates/roles.yaml"]
Expect(roles).Should(ContainSubstring("kind: ServiceAccount"))
Expect(roles).Should(ContainSubstring(`name: "spire-external"`))
Expect(roles).Should(ContainSubstring(`namespace: "spire-ext"`))
})
It("binds the external server's downstream RBAC to a Group subject", func() {
objs, err := ValueStringRender(chart, `
spire-server:
externalServer: true
externalServerSubject:
kind: Group
name: spire-admins
`)
Expect(err).Should(Succeed())
roles := objs["spire/charts/spire-server/templates/roles.yaml"]
Expect(roles).Should(ContainSubstring("apiGroup: rbac.authorization.k8s.io"))
Expect(roles).Should(ContainSubstring("kind: Group"))
Expect(roles).Should(ContainSubstring(`name: "spire-admins"`))
})
})
Describe("spire-server.updateStrategy", func() {
It("maps to spec.strategy when kind is deployment", func() {
objs, err := ValueStringRender(chart, `
spire-server:
kind: deployment
persistence:
type: emptyDir
keyManager:
disk:
enabled: false
memory:
enabled: true
dataStore:
sql:
databaseType: postgres
host: db.example.org
updateStrategy:
type: Recreate
`)
Expect(err).Should(Succeed())
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("kind: Deployment"))
Expect(serverResource).Should(ContainSubstring("\n strategy:\n type: Recreate\n"))
})
It("maps to spec.updateStrategy when kind is statefulset", func() {
objs, err := ValueStringRender(chart, `
spire-server:
updateStrategy:
type: OnDelete
`)
Expect(err).Should(Succeed())
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("kind: StatefulSet"))
Expect(serverResource).Should(ContainSubstring("\n updateStrategy:\n type: OnDelete\n"))
})
It("renders neither field when left unset", func() {
objs, err := ValueStringRender(chart, `
spire-server:
replicaCount: 1
`)
Expect(err).Should(Succeed())
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).ShouldNot(ContainSubstring("\n strategy:"))
Expect(serverResource).ShouldNot(ContainSubstring("\n updateStrategy:"))
})
})
Describe("spire-server.kind.deployment.sqlite3", func() {
deployment := func(sql string) string {
return `
spire-server:
kind: deployment
persistence:
type: emptyDir
keyManager:
disk:
enabled: false
memory:
enabled: true
updateStrategy:
type: Recreate
dataStore:
sql:
` + sql
}
It("renders a Deployment when the sqlite3 datastore is in memory", func() {
objs, err := ValueStringRender(chart, deployment(` inMemory: true
`))
Expect(err).Should(Succeed())
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("kind: Deployment"))
Expect(serverResource).ShouldNot(ContainSubstring("kind: StatefulSet"))
})
It("rejects a file backed sqlite3 datastore", func() {
_, err := ValueStringRender(chart, deployment(` inMemory: false
`))
Expect(err).Should(MatchError(ContainSubstring("sqlite3 can only be used in memory")))
})
})
Describe("spire-server.dataStore.sql.inMemory", func() {
It("builds a shared cache connection string and ignores file", func() {
objs, err := ValueStringRender(chart, `
spire-server:
dataStore:
sql:
inMemory: true
file: /run/spire/data/datastore.sqlite3
`)
Expect(err).Should(Succeed())
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
Should(ContainSubstring(`"connection_string": "memdb?mode=memory\u0026cache=shared"`))
})
It("keeps the file connection string when left off", func() {
objs, err := ValueStringRender(chart, `
spire-server:
dataStore:
sql:
file: /run/spire/data/datastore.sqlite3
`)
Expect(err).Should(Succeed())
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
Should(ContainSubstring(`"connection_string": "/run/spire/data/datastore.sqlite3"`))
})
})
Describe("spire-server.dataStore.sql.inMemory warnings", func() {
notes := func(values string) string {
objs, err := ValueStringRender(chart, values)
ExpectWithOffset(1, err).Should(Succeed())
return objs["spire/templates/NOTES.txt"]
}
safe := `
spire-server:
dataStore:
sql:
inMemory: true
controllerManager:
enabled: true
reconcile:
clusterStaticEntries: true
upstreamAuthority:
vault:
enabled: true
`
It("stays quiet on the default values", func() {
Expect(notes(`spire-server: {}`)).ShouldNot(ContainSubstring("Warning: dataStore.sql.inMemory"))
})
It("stays quiet when entries are reconciled and a CA is upstream", func() {
Expect(notes(safe)).ShouldNot(ContainSubstring("Warning: dataStore.sql.inMemory"))
})
It("warns when nothing recreates the registration entries", func() {
Expect(notes(`
spire-server:
dataStore:
sql:
inMemory: true
controllerManager:
enabled: false
`)).Should(ContainSubstring("nothing recreates them"))
})
It("warns when the CA is also in memory with no upstream authority", func() {
Expect(notes(`
spire-server:
dataStore:
sql:
inMemory: true
controllerManager:
enabled: true
reconcile:
clusterStaticEntries: true
keyManager:
disk:
enabled: false
memory:
enabled: true
`)).Should(ContainSubstring("mints a new CA on every restart"))
})
It("stays quiet on a deployment that cannot surge", func() {
Expect(notes(safe + `
kind: deployment
persistence:
type: emptyDir
keyManager:
disk:
enabled: false
memory:
enabled: true
updateStrategy:
type: Recreate
`)).ShouldNot(ContainSubstring("Warning: dataStore.sql.inMemory"))
})
})
Describe("spire-server.updateStrategy surge guard", func() {
deployment := func(strategy string) string {
return `
spire-server:
kind: deployment
persistence:
type: emptyDir
keyManager:
disk:
enabled: false
memory:
enabled: true
dataStore:
sql:
inMemory: true
` + strategy
}
It("rejects an in-memory deployment that can surge", func() {
_, err := ValueStringRender(chart, deployment(``))
Expect(err).Should(MatchError(ContainSubstring("must not surge")))
})
It("rejects an explicit rolling update that can surge", func() {
_, err := ValueStringRender(chart, deployment(` updateStrategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
`))
Expect(err).Should(MatchError(ContainSubstring("must not surge")))
})
It("accepts Recreate", func() {
_, err := ValueStringRender(chart, deployment(` updateStrategy:
type: Recreate
`))
Expect(err).Should(Succeed())
})
It("accepts a rolling update pinned to maxSurge 0", func() {
_, err := ValueStringRender(chart, deployment(` updateStrategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 0
maxUnavailable: 1
`))
Expect(err).Should(Succeed())
})
It("accepts maxSurge expressed as a percentage", func() {
_, err := ValueStringRender(chart, deployment(` updateStrategy:
rollingUpdate:
maxSurge: 0%
`))
Expect(err).Should(Succeed())
})
It("leaves a file backed statefulset alone", func() {
_, err := ValueStringRender(chart, `
spire-server:
updateStrategy:
type: RollingUpdate
`)
Expect(err).Should(Succeed())
})
})
Describe("spire-server webhook patch order", func() {
It("preserves the rendered webhook order in every strategic-merge hook", func() {
objs, err := ValueStringRender(chart, `
global:
installAndUpgradeHooks:
enabled: true
spire-server:
enabled: true
controllerManager:
enabled: true
`)
Expect(err).Should(Succeed())
canonicalDocuments, err := decodeRenderedDocuments(objs["spire/charts/spire-server/templates/controller-manager-webhook.yaml"])
Expect(err).Should(Succeed())
Expect(canonicalDocuments).Should(HaveLen(1))
Expect(canonicalDocuments[0].Kind).Should(Equal("ValidatingWebhookConfiguration"))
canonicalNames := make([]string, 0, len(canonicalDocuments[0].Webhooks))
for _, webhook := range canonicalDocuments[0].Webhooks {
canonicalNames = append(canonicalNames, webhook.Name)
}
for _, hook := range []struct {
name string
template string
}{
{name: "post-install", template: "spire/charts/spire-server/templates/post-install-hook.yaml"},
{name: "pre-upgrade", template: "spire/charts/spire-server/templates/pre-upgrade-hook.yaml"},
{name: "post-upgrade", template: "spire/charts/spire-server/templates/post-upgrade-hook.yaml"},
} {
documents, err := decodeRenderedDocuments(objs[hook.template])
Expect(err).Should(Succeed())
var jobs []renderedDocument
for _, document := range documents {
if document.Kind == "Job" && document.Metadata.Annotations["helm.sh/hook"] == hook.name {
jobs = append(jobs, document)
}
}
Expect(jobs).Should(HaveLen(1), hook.name)
actualNames, err := patchWebhookNames(jobs[0])
Expect(err).Should(Succeed())
Expect(actualNames).Should(Equal(canonicalNames), hook.name)
}
})
})
Describe("spire-server webhook hooks disabled", func() {
It("uses the configured failure policy and omits lifecycle Jobs", func() {
objs, err := ValueStringRender(chart, `
global:
installAndUpgradeHooks:
enabled: false
spire-server:
controllerManager:
enabled: true
validatingWebhookConfiguration:
failurePolicy: Fail
`)
Expect(err).Should(Succeed())
canonicalDocuments, err := decodeRenderedDocuments(objs["spire/charts/spire-server/templates/controller-manager-webhook.yaml"])
Expect(err).Should(Succeed())
Expect(canonicalDocuments).Should(HaveLen(1))
Expect(canonicalDocuments[0].Webhooks).Should(HaveLen(2))
for _, webhook := range canonicalDocuments[0].Webhooks {
Expect(webhook.FailurePolicy).Should(Equal("Fail"))
}
for _, template := range []string{
"spire/charts/spire-server/templates/post-install-hook.yaml",
"spire/charts/spire-server/templates/pre-upgrade-hook.yaml",
"spire/charts/spire-server/templates/post-upgrade-hook.yaml",
} {
documents, err := decodeRenderedDocuments(objs[template])
Expect(err).Should(Succeed())
for _, document := range documents {
Expect(document.Kind).ShouldNot(Equal("Job"), template)
}
}
})
})
Describe("spire-server.dataStore.sql.postgres passwordless", func() {
It("omits password and the -dbpw Secret for cert auth with an empty password", func() {
objs, err := ValueStringRender(chart, `
spire-server:
dataStore:
sql:
databaseType: postgres
host: db.example.org
username: spire
password: ""
rootCAPath: /run/spire/db-ca/ca.crt
clientCertPath: /run/spire/db-certs/tls.crt
clientKeyPath: /run/spire/db-certs/tls.key
`)
Expect(err).Should(Succeed())
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
ShouldNot(ContainSubstring("password=${DBPW}"))
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
Should(ContainSubstring("sslrootcert=/run/spire/db-ca/ca.crt"))
Expect(objs["spire/charts/spire-server/templates/secret.yaml"]).
ShouldNot(ContainSubstring("kind: Secret"))
Expect(objs["spire/charts/spire-server/templates/server-resource.yaml"]).
ShouldNot(ContainSubstring("name: DBPW"))
})
It("keeps the password token and DBPW env when an external secret provides the password", func() {
objs, err := ValueStringRender(chart, `
spire-server:
dataStore:
sql:
databaseType: postgres
host: db.example.org
username: spire
password: ""
externalSecret:
enabled: true
name: my-db-secret
key: password
`)
Expect(err).Should(Succeed())
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
Should(ContainSubstring("password=${DBPW}"))
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("name: DBPW"))
Expect(serverResource).Should(ContainSubstring("name: my-db-secret"))
})
It("keeps the RODBPW env when a read-only external secret provides the password", func() {
objs, err := ValueStringRender(chart, `
spire-server:
dataStore:
sql:
databaseType: postgres
host: db.example.org
username: spire
password: ""
rootCAPath: /run/spire/db-ca/ca.crt
clientCertPath: /run/spire/db-certs/tls.crt
clientKeyPath: /run/spire/db-certs/tls.key
readOnly:
enabled: true
host: ro.example.org
username: spire
password: ""
externalSecret:
enabled: true
name: my-ro-db-secret
key: password
`)
Expect(err).Should(Succeed())
Expect(objs["spire/charts/spire-server/templates/configmap.yaml"]).
Should(ContainSubstring("password=${RODBPW}"))
serverResource := objs["spire/charts/spire-server/templates/server-resource.yaml"]
Expect(serverResource).Should(ContainSubstring("name: RODBPW"))
Expect(serverResource).Should(ContainSubstring("name: my-ro-db-secret"))
})
}) })
}) })