diff --git a/.github/tests/common.sh b/.github/tests/common.sh index 3211e38..7d5323b 100755 --- a/.github/tests/common.sh +++ b/.github/tests/common.sh @@ -55,6 +55,7 @@ print_spire_workload_status () { | Namespace | Workload | Status | | --------- | ---------------------------------------------- | ------ | | ${ns1} | ${release_name}-server |
$(k_rollout_status "${ns1}" statefulset "${release_name}-server") |
+| ${ns1} | ${release_name}-server | $(k_rollout_status "${ns1}" deployments.apps "${release_name}-server") |
| ${ns2} | ${release_name}-spiffe-csi-driver | $(k_rollout_status "${ns2}" daemonset "${release_name}-spiffe-csi-driver") |
| ${ns2} | ${release_name}-agent | $(k_rollout_status "${ns2}" daemonset "${release_name}-agent") |
| ${ns1} | ${release_name}-spiffe-oidc-discovery-provider | $(k_rollout_status "${ns1}" deployments.apps "${release_name}-spiffe-oidc-discovery-provider") |
diff --git a/charts/spire/README.md b/charts/spire/README.md
index 570d01a..be050e8 100644
--- a/charts/spire/README.md
+++ b/charts/spire/README.md
@@ -244,11 +244,12 @@ Now you can interact with the Spire agent socket from your own application. The
### Spire server parameters
-| Name | Description | Value |
-| ---------------------------------------- | --------------------------------------------- | -------- |
-| `spire-server.enabled` | Flag to enable Spire server | `true` |
-| `spire-server.nameOverride` | Overrides the name of Spire server pods | `server` |
-| `spire-server.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` |
+| Name | Description | Value |
+| ---------------------------------------- | ------------------------------------------------------------------------- | ------------- |
+| `spire-server.enabled` | Flag to enable Spire server | `true` |
+| `spire-server.nameOverride` | Overrides the name of Spire server pods | `server` |
+| `spire-server.kind` | Run spire server as deployment/statefulset. This feature is experimental. | `statefulset` |
+| `spire-server.controllerManager.enabled` | Enable controller manager and provision CRD's | `true` |
### Spire agent parameters
diff --git a/charts/spire/charts/spire-server/README.md b/charts/spire/charts/spire-server/README.md
index 243f7b0..1ecad75 100644
--- a/charts/spire/charts/spire-server/README.md
+++ b/charts/spire/charts/spire-server/README.md
@@ -86,6 +86,7 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr
| `image.repository` | The repository within the registry | `spiffe/spire-server` |
| `image.pullPolicy` | The image pull policy | `IfNotPresent` |
| `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` |
| `imagePullSecrets` | Pull secrets for images | `[]` |
| `nameOverride` | Name override | `""` |
| `crNameOverride` | Name override for any custom resources | `""` |
diff --git a/charts/spire/charts/spire-server/templates/_helpers.tpl b/charts/spire/charts/spire-server/templates/_helpers.tpl
index cd81b6a..87d8060 100644
--- a/charts/spire/charts/spire-server/templates/_helpers.tpl
+++ b/charts/spire/charts/spire-server/templates/_helpers.tpl
@@ -5,6 +5,17 @@ Expand the name of the chart.
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
+{{/*
+Spire Server deployment/statefulset
+*/}}
+{{- define "spire-server.kind" -}}
+{{- if not (has .Values.kind (list "statefulset" "deployment")) -}}
+ {{- fail "Unsupported deployment type" -}}
+{{- else -}}
+ {{- .Values.kind -}}
+{{- end -}}
+{{- 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).
diff --git a/charts/spire/charts/spire-server/templates/hpa.yaml b/charts/spire/charts/spire-server/templates/hpa.yaml
index 4c1c41c..65b195e 100644
--- a/charts/spire/charts/spire-server/templates/hpa.yaml
+++ b/charts/spire/charts/spire-server/templates/hpa.yaml
@@ -9,7 +9,11 @@ metadata:
spec:
scaleTargetRef:
apiVersion: apps/v1
+ {{- if eq .Values.kind "statefulset" }}
kind: StatefulSet
+ {{- else if eq .Values.kind "deployment" }}
+ kind: Deployment
+ {{- end }}
name: {{ include "spire-server.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
{{- if and (eq .Values.dataStore.sql.databaseType "sqlite3") .Values.autoscaling.enabled (gt (int .Values.autoscaling.maxReplicas) 1) }}
diff --git a/charts/spire/charts/spire-server/templates/pre-delete-hook.yaml b/charts/spire/charts/spire-server/templates/pre-delete-hook.yaml
index 86226a1..2a14be9 100644
--- a/charts/spire/charts/spire-server/templates/pre-delete-hook.yaml
+++ b/charts/spire/charts/spire-server/templates/pre-delete-hook.yaml
@@ -21,7 +21,7 @@ metadata:
"helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed
rules:
- apiGroups: ["apps"]
- resources: ["statefulsets"]
+ resources: ["{{ include "spire-server.kind" . }}s"]
resourceNames: [{{ include "spire-server.fullname" . | quote }}]
verbs: ["get", "delete"]
- apiGroups: [""]
@@ -73,7 +73,7 @@ spec:
- delete
- -n
- {{ include "spire-server.namespace" . }}
- - statefulset
+ - {{ include "spire-server.kind" . }}
- {{ include "spire-server.fullname" . }}
- --wait
- name: pre-delete-check
diff --git a/charts/spire/charts/spire-server/templates/statefulset.yaml b/charts/spire/charts/spire-server/templates/server-resource.yaml
similarity index 95%
rename from charts/spire/charts/spire-server/templates/statefulset.yaml
rename to charts/spire/charts/spire-server/templates/server-resource.yaml
index 2d3f48a..8a0634b 100644
--- a/charts/spire/charts/spire-server/templates/statefulset.yaml
+++ b/charts/spire/charts/spire-server/templates/server-resource.yaml
@@ -3,11 +3,30 @@
{{- $configSum3 := (include (print $.Template.BasePath "/controller-manager-configmap.yaml") . | sha256sum) }}
{{- $configSumTornjak := (include (print $.Template.BasePath "/tornjak-config.yaml") . | sha256sum) }}
{{- $fullname := include "spire-server.fullname" . }}
-{{- if not (has .Values.persistence.type (list "pvc" "hostPath" "emptyDir")) }}
-{{- fail "persistence.type must be one of [\"pvc\", \"hostPath\", \"emptyDir\"]" }}
+
+{{- if eq .Values.kind "statefulset" }}
+{{- if not (has .Values.persistence.type (list "pvc" "hostPath" "emptyDir")) }}
+{{- fail "persistence.type must be one of [\"pvc\", \"hostPath\", \"emptyDir\"]" }}
+{{- end }}
+{{- else if eq .Values.kind "deployment" }}
+{{- if (has .Values.persistence.type (list "pvc" "hostPath")) }}
+{{- fail "When running as deployment, persistence can't be set. 'persistence.type' must be [\"emptyDir\"]" }}
+{{- end }}
+{{- if (eq .Values.dataStore.sql.databaseType "sqlite3") }}
+{{- fail "When running as deployment, sqlite3 can't be used." }}
+{{- end }}
+{{- 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." }}
+{{- end }}
+{{- else }}
+{{- fail "Unsupported kind." }}
{{- end }}
apiVersion: apps/v1
+{{- if eq .Values.kind "statefulset" }}
kind: StatefulSet
+{{- else if eq .Values.kind "deployment" }}
+kind: Deployment
+{{- end }}
metadata:
name: {{ include "spire-server.fullname" . }}
namespace: {{ include "spire-server.namespace" . }}
@@ -21,7 +40,9 @@ spec:
{{- end }}
replicas: {{ .Values.replicaCount }}
{{- end }}
+ {{- if eq .Values.kind "statefulset" }}
serviceName: {{ include "spire-server.fullname" . }}
+ {{- end }}
selector:
matchLabels:
{{- include "spire-server.selectorLabels" . | nindent 6 }}
@@ -491,4 +512,4 @@ spec:
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass }}
{{- end }}
- {{- end }}
+ {{- end }}
\ No newline at end of file
diff --git a/charts/spire/charts/spire-server/values.yaml b/charts/spire/charts/spire-server/values.yaml
index 501cda8..5c449be 100644
--- a/charts/spire/charts/spire-server/values.yaml
+++ b/charts/spire/charts/spire-server/values.yaml
@@ -20,6 +20,9 @@ image:
pullPolicy: IfNotPresent
tag: ""
+## @param kind Define SPIRE server deployment type. Can be statefulset/deployment. Defaults to statefulset if not set. This feature is experimental.
+kind: statefulset
+
## @param imagePullSecrets [array] Pull secrets for images
imagePullSecrets: []
diff --git a/charts/spire/values.yaml b/charts/spire/values.yaml
index e5de054..81558a3 100644
--- a/charts/spire/values.yaml
+++ b/charts/spire/values.yaml
@@ -108,6 +108,8 @@ spire-server:
enabled: true
## @param spire-server.nameOverride Overrides the name of Spire server pods
nameOverride: server
+ ## @param spire-server.kind Run spire server as deployment/statefulset. This feature is experimental.
+ kind: statefulset
controllerManager:
## @param spire-server.controllerManager.enabled Enable controller manager and provision CRD's
enabled: true
diff --git a/examples/stateless-server/README.md b/examples/stateless-server/README.md
new file mode 100644
index 0000000..4475fae
--- /dev/null
+++ b/examples/stateless-server/README.md
@@ -0,0 +1,23 @@
+# Example stateless server
+
+To install Spire Server as a deployment(stateless), you need to use an external database. This runs spire-server as stateless microservice enabling HA.
+
+### WARNING
+The following configurations are not supported for running spire-server as deployment.
+1. spire-server.persistence.type
+2. spire-server.dataStore.sql.databaseType: "sqlite3"
+3. spire-server.keyManager.disk
+4. spire-server.tornjak
+
+If manually deploying for testing, you can create an incluster or use an external database and put the database password into an environment variable.
+
+Next, edit your-values.yaml with your settings as described in the [production install instructions](https://artifacthub.io/packages/helm/spiffe/spire#production). Check it into your git repo if using one.
+
+Then, deploy the chart pointing at your mysql instance like so:
+
+```shell
+helm upgrade --install --namespace spire-mgmt spire spire --repo https://spiffe.github.io/helm-charts-hardened/ -f examples/stateless-server/values.yaml --set "spire-server.dataStore.sql.password=${DBPW}" -f your-values.yaml
+```
+
+See the [production install instructions](https://artifacthub.io/packages/helm/spiffe/spire#production) for production recommendations.
+See [values.yaml](./values.yaml) for more details on the chart configurations to achieve this setup.
diff --git a/examples/stateless-server/run-tests.sh b/examples/stateless-server/run-tests.sh
new file mode 100755
index 0000000..6f3bd7a
--- /dev/null
+++ b/examples/stateless-server/run-tests.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+set -xe
+
+SCRIPT="$(readlink -f "$0")"
+SCRIPTPATH="$(dirname "${SCRIPT}")"
+TESTDIR="${SCRIPTPATH}/../../.github/tests"
+DEPS="${TESTDIR}/dependencies"
+
+# shellcheck source=/dev/null
+source "${SCRIPTPATH}/../../.github/scripts/parse-versions.sh"
+# shellcheck source=/dev/null
+source "${TESTDIR}/common.sh"
+
+CLEANUP=1
+
+for i in "$@"; do
+ case $i in
+ -c)
+ CLEANUP=0
+ shift # past argument=value
+ ;;
+ esac
+done
+
+teardown() {
+ print_helm_releases
+ print_spire_workload_status spire-server
+ print_spire_workload_status spire-system
+
+ if [[ "$1" -ne 0 ]]; then
+ get_namespace_details spire-server
+ get_namespace_details spire-system
+ fi
+
+ if [ "${CLEANUP}" -eq 1 ]; then
+ helm uninstall --namespace "spire-server" spire 2>/dev/null || true
+ helm uninstall --namespace mysql mysql 2>/dev/null || true
+ kubectl delete ns spire-server 2>/dev/null || true
+ kubectl delete ns spire-system 2>/dev/null || true
+ fi
+}
+
+trap 'EC=$? && trap - SIGTERM && teardown $EC' SIGINT SIGTERM EXIT
+
+kubectl create namespace spire-system --dry-run=client -o yaml | kubectl apply -f -
+kubectl label namespace spire-system pod-security.kubernetes.io/enforce=privileged || true
+kubectl create namespace spire-server --dry-run=client -o yaml | kubectl apply -f -
+kubectl label namespace spire-server pod-security.kubernetes.io/enforce=restricted || true
+
+helm upgrade --install mysql mysql --version "$VERSION_MYSQL" --repo "$HELM_REPO_MYSQL" \
+ --namespace spire-server \
+ --values "${DEPS}/mysql.yaml" \
+ --wait
+
+helm upgrade --install --namespace "spire-server" \
+ --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/values.yaml,${SCRIPTPATH}/../misc/values-node-pod-antiaffinity.yaml" \
+ --set 'spire-server.dataStore.sql.password=sp1ff3Test' --wait spire charts/spire
+helm test --namespace "spire-server" spire
diff --git a/examples/stateless-server/values.yaml b/examples/stateless-server/values.yaml
new file mode 100644
index 0000000..f9f2753
--- /dev/null
+++ b/examples/stateless-server/values.yaml
@@ -0,0 +1,18 @@
+spire-server:
+ deploymentType: deployment
+ replicaCount: 2
+ persistence:
+ type: emptyDir
+ keyManager:
+ disk:
+ enabled: false
+ memory:
+ enabled: true
+ dataStore:
+ sql:
+ databaseType: mysql
+ databaseName: spire-server
+ host: mysql
+ port: 3306
+ username: spire
+ # password: CHANGE_ME