diff --git a/.github/tests/charts.json b/.github/tests/charts.json index 0aa00f75e..221f97ec6 100644 --- a/.github/tests/charts.json +++ b/.github/tests/charts.json @@ -2,12 +2,12 @@ { "name": "kube-prometheus-stack", "repo": "https://prometheus-community.github.io/helm-charts", - "version": "56.20.0" + "version": "57.0.3" }, { "name": "cert-manager", "repo": "https://charts.jetstack.io", - "version": "v1.14.3" + "version": "v1.14.4" }, { "name": "ingress-nginx", @@ -17,11 +17,11 @@ { "name": "mysql", "repo": "https://charts.bitnami.com/bitnami", - "version": "9.22.0" + "version": "9.23.0" }, { "name": "postgresql", "repo": "https://charts.bitnami.com/bitnami", - "version": "14.2.3" + "version": "14.3.3" } ] diff --git a/.github/tests/common.sh b/.github/tests/common.sh index 6cb4f6e02..3211e3863 100755 --- a/.github/tests/common.sh +++ b/.github/tests/common.sh @@ -70,3 +70,23 @@ $(helm ls -A | sed 's/\t/ | /g' | sed 's/^/| /' | sed 's/$/ |/' | sed '/^| NAME. EOF } + +# Used just for testing. You should provide your own values as described in the install instructions. +common_test_your_values () { +cat > /tmp/$$.example-your-values.yaml < 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 -version: 0.18.2 +version: 0.19.0 appVersion: "1.9.1" keywords: ["spiffe", "spire", "spire-server", "spire-agent", "oidc", "spire-controller-manager"] home: https://github.com/spiffe/helm-charts-hardened/tree/main/charts/spire diff --git a/charts/spire/README.md b/charts/spire/README.md index 013583510..570d01ac6 100644 --- a/charts/spire/README.md +++ b/charts/spire/README.md @@ -1,6 +1,6 @@ # spire -![Version: 0.18.2](https://img.shields.io/badge/Version-0.18.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.9.1](https://img.shields.io/badge/AppVersion-1.9.1-informational?style=flat-square) +![Version: 0.19.0](https://img.shields.io/badge/Version-0.19.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.9.1](https://img.shields.io/badge/AppVersion-1.9.1-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) 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. @@ -75,7 +75,11 @@ kubectl delete crds clusterfederatedtrustdomains.spire.spiffe.io clusterspiffeid We only support upgrading one major version at a time. Version skipping isn't supported. -### 0.18.x +### 0.19.X + +- The spire-agent daemonset gained a new label. For those disabling the upgrade hooks, you need to delete the spire-agent daemonset before issuing the helm upgrade. + +### 0.18.X - SPIRE no longer emits x509UniqueIdentifiers in x509-SVIDS by default. The old behavior can be reenabled with spire-server.credentialComposer.uniqueID.enabled=true. See https://github.com/spiffe/spire/pull/4862 for details. - SPIRE agents will now automatically reattest when they can. The old behavior can be reenabled with spire-agent.disableReattestToRenew=true. See https://github.com/spiffe/spire/pull/4791 for details. diff --git a/charts/spire/charts/spiffe-oidc-discovery-provider/README.md b/charts/spire/charts/spiffe-oidc-discovery-provider/README.md index 0dc9cd0b0..e5eb881b8 100644 --- a/charts/spire/charts/spiffe-oidc-discovery-provider/README.md +++ b/charts/spire/charts/spiffe-oidc-discovery-provider/README.md @@ -115,11 +115,11 @@ A Helm chart to install the SPIFFE OIDC discovery provider. | `tests.bash.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `tests.bash.image.repository` | The repository within the registry | `chainguard/bash` | | `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:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669` | +| `tests.bash.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2` | | `tests.toolkit.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `tests.toolkit.image.repository` | The repository within the registry | `chainguard/slim-toolkit-debug` | | `tests.toolkit.image.pullPolicy` | The image pull policy | `IfNotPresent` | -| `tests.toolkit.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:606810cf1076a226dfb85fa4102ee0ed2d8e2b7c7a8a2a53f9788c65501ecca8` | +| `tests.toolkit.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:faaccf708167925bbbf1dbfcbaf6ab733a170074bce7901542a0c38b87838842` | | `tests.step.image.registry` | The OCI registry to pull the image from | `docker.io` | | `tests.step.image.repository` | The repository within the registry | `smallstep/step-cli` | | `tests.step.image.pullPolicy` | The image pull policy | `IfNotPresent` | diff --git a/charts/spire/charts/spiffe-oidc-discovery-provider/values.yaml b/charts/spire/charts/spiffe-oidc-discovery-provider/values.yaml index a7dfd1010..728a83790 100644 --- a/charts/spire/charts/spiffe-oidc-discovery-provider/values.yaml +++ b/charts/spire/charts/spiffe-oidc-discovery-provider/values.yaml @@ -328,7 +328,7 @@ tests: registry: cgr.dev repository: chainguard/bash pullPolicy: IfNotPresent - tag: latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669 + tag: latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2 toolkit: ## @param tests.toolkit.image.registry The OCI registry to pull the image from @@ -340,7 +340,7 @@ tests: registry: cgr.dev repository: chainguard/slim-toolkit-debug pullPolicy: IfNotPresent - tag: latest@sha256:606810cf1076a226dfb85fa4102ee0ed2d8e2b7c7a8a2a53f9788c65501ecca8 + tag: latest@sha256:faaccf708167925bbbf1dbfcbaf6ab733a170074bce7901542a0c38b87838842 step: ## @param tests.step.image.registry The OCI registry to pull the image from diff --git a/charts/spire/charts/spire-agent/README.md b/charts/spire/charts/spire-agent/README.md index c4b10d2a1..f3af4fff0 100644 --- a/charts/spire/charts/spire-agent/README.md +++ b/charts/spire/charts/spire-agent/README.md @@ -69,12 +69,12 @@ A Helm chart to install the SPIRE agent. | `waitForIt.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `waitForIt.image.repository` | The repository within the registry | `chainguard/wait-for-it` | | `waitForIt.image.pullPolicy` | The image pull policy | `IfNotPresent` | -| `waitForIt.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:caead414307e81dbdd86d30662fdfe1b999dd4ce8a10fa667dab3438d0eed193` | +| `waitForIt.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:1f449e8972f7ffc876cafae20f58e2ff9015141b02cfc637a71ce9a5dddd73ba` | | `waitForIt.resources` | Resource requests and limits | `{}` | | `fsGroupFix.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `fsGroupFix.image.repository` | The repository within the registry | `chainguard/bash` | | `fsGroupFix.image.pullPolicy` | The image pull policy | `Always` | -| `fsGroupFix.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669` | +| `fsGroupFix.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2` | | `fsGroupFix.resources` | Specify resource needs as per https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | `{}` | | `keyManager.memory.enabled` | Enable the memory based Key Manager | `true` | | `nodeAttestor.k8sPsat.enabled` | Enable Psat k8s Node Attestor | `true` | @@ -110,7 +110,7 @@ A Helm chart to install the SPIRE agent. | `socketAlternate.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `socketAlternate.image.repository` | The repository within the registry | `chainguard/bash` | | `socketAlternate.image.pullPolicy` | The image pull policy | `Always` | -| `socketAlternate.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669` | +| `socketAlternate.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2` | | `socketAlternate.resources` | Specify resource needs as per https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | `{}` | | `priorityClassName` | Priority class assigned to daemonset pods. Can be auto set with global.recommendations.priorityClassName. | `""` | | `extraEnvVars` | Extra environment variables to be added to the Spire Agent container | `[]` | @@ -126,6 +126,12 @@ A Helm chart to install the SPIRE agent. | `experimental.enabled` | Allow configuration of experimental features | `false` | | `experimental.syncInterval` | Sync interval with SPIRE server with exponential backoff | `5s` | | `experimental.featureFlags` | List of developer feature flags | `[]` | +| `agents` | Configure multiple agent DaemonSets. Useful when you have different node types and nodeAttestors | `{}` | +| `installAndUpgradeHook.enabled` | Enable Helm hook to autofix common install/upgrade issues (should be disabled when using `helm template`) | `true` | +| `tools.kubectl.image.registry` | The OCI registry to pull the image from | `docker.io` | +| `tools.kubectl.image.repository` | The repository within the registry | `rancher/kubectl` | +| `tools.kubectl.image.pullPolicy` | The image pull policy | `IfNotPresent` | +| `tools.kubectl.image.tag` | Overrides the image tag whose default is the chart appVersion | `""` | | `sockets.hostBasePath` | Path on which the agent socket is made available when admin.mountOnHost is true | `/run/spire/agent/sockets` | | `sockets.admin.enabled` | Enable the admin socket. Useful for admin tasks or the Delegated Identity API. | `false` | | `sockets.admin.mountOnHost` | Enable the admin socket to be visible on the host. | `false` | diff --git a/charts/spire/charts/spire-agent/templates/configmap.yaml b/charts/spire/charts/spire-agent/templates/configmap.yaml index 1fb312bba..4de965b10 100644 --- a/charts/spire/charts/spire-agent/templates/configmap.yaml +++ b/charts/spire/charts/spire-agent/templates/configmap.yaml @@ -1,3 +1,4 @@ +{{- define "spire-agent.check-config-values" -}} {{- include "spire-lib.check-strict-mode" (list . "clusterName must be set" (eq (include "spire-lib.cluster-name" .) "example-cluster"))}} {{- include "spire-lib.check-strict-mode" (list . "trustDomain must be set" (eq (include "spire-lib.trust-domain" .) "example.org"))}} {{- range $type, $tvals := .Values.customPlugins }} @@ -21,6 +22,7 @@ {{- if hasPrefix (.Values.socketPath | dir | clean) (.Values.sockets.hostBasePath | clean) }} {{- fail "The sockets.hostBasePath can not be located under the socketPath direcotry" }} {{- end }} +{{- end }} {{- define "spire-agent.yaml-config" -}} agent: {{- if .Values.disableReattestToRenew }} @@ -132,10 +134,22 @@ telemetry: port: {{ .Values.telemetry.prometheus.port }} {{- end }} {{- end }} +{{- $root := . }} +{{- range $name := (concat (list "default") (keys .Values.agents)) | uniq }} +{{- with (dict "Release" $root.Release "Chart" $root.Chart "Values" (deepCopy $root.Values)) }} +{{- $nameSuffix := "" }} +{{- if ne $name "default" }} +{{- $nameSuffix = printf "-%s" $name }} +{{- end }} +{{- if hasKey $root.Values.agents $name }} +{{- $_ := set . "Values" (mergeOverwrite .Values (index $root.Values.agents $name)) }} +{{- end }} +{{- include "spire-agent.check-config-values" . }} +--- apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . }}{{ $nameSuffix }} namespace: {{ include "spire-agent.namespace" . }} {{- with .Values.configMap.annotations }} annotations: @@ -144,3 +158,5 @@ metadata: data: agent.conf: | {{- include "spire-lib.reformat-and-yaml2json" (dict "config" (include "spire-agent.yaml-config" .) "root" .) | nindent 4 }} +{{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-agent/templates/daemonset.yaml b/charts/spire/charts/spire-agent/templates/daemonset.yaml index d94cd9667..db8fe9dbb 100644 --- a/charts/spire/charts/spire-agent/templates/daemonset.yaml +++ b/charts/spire/charts/spire-agent/templates/daemonset.yaml @@ -1,4 +1,14 @@ {{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }} +{{- $root := . }} +{{- range $name := (concat (list "default") (keys .Values.agents)) | uniq }} +{{- with (dict "Release" $root.Release "Chart" $root.Chart "Values" (deepCopy $root.Values)) }} +{{- $nameSuffix := "" }} +{{- if ne $name "default" }} +{{- $nameSuffix = printf "-%s" $name }} +{{- end }} +{{- if hasKey $root.Values.agents $name }} +{{- $_ := set . "Values" (mergeOverwrite .Values (index $root.Values.agents $name)) }} +{{- end }} {{- $podSecurityContext := fromYaml (include "spire-lib.podsecuritycontext" .) }} {{- $mainSecurityContext := deepCopy .Values.securityContext }} {{- if .Values.nodeAttestor.tpmDirect.enabled }} @@ -8,17 +18,20 @@ {{- $cbh := eq (include "spire-agent.connect-by-hostname" .) "true" }} {{- $socketAlternateNames := index (include "spire-agent.socket-alternate-names" . | fromYaml) "names" }} {{- $socketPath := include "spire-agent.socket-path" . }} +--- apiVersion: apps/v1 kind: DaemonSet metadata: - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . }}{{ $nameSuffix }} namespace: {{ include "spire-agent.namespace" . }} labels: {{- include "spire-agent.labels" . | nindent 4 }} + app.kubernetes.io/component: {{ $name }} spec: selector: matchLabels: {{- include "spire-agent.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: {{ $name }} {{- with .Values.updateStrategy }} updateStrategy: {{- if not (has .type (list "RollingUpdate" "OnDelete")) }} @@ -40,6 +53,7 @@ spec: {{- end }} labels: {{- include "spire-agent.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: {{ $name }} {{- with .Values.podLabels }} {{- toYaml . | nindent 8 }} {{- end }} @@ -257,7 +271,7 @@ spec: {{- if eq (len .Values.trustBundleURL) 0 }} - name: spire-bundle configMap: - name: {{ include "spire-lib.bundle-configmap" . }} + name: {{ include "spire-lib.bundle-configmap" . }}{{ $nameSuffix }} {{- end }} {{- if .Values.nodeAttestor.tpmDirect.enabled }} - name: tpm-direct @@ -287,3 +301,5 @@ spec: {{- if gt (len .Values.extraVolumes) 0 }} {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} +{{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-agent/templates/pre-upgrade-hook.yaml b/charts/spire/charts/spire-agent/templates/pre-upgrade-hook.yaml new file mode 100644 index 000000000..e28c2bc03 --- /dev/null +++ b/charts/spire/charts/spire-agent/templates/pre-upgrade-hook.yaml @@ -0,0 +1,77 @@ +{{- if eq ((dig "installAndUpgradeHooks" "enabled" .Values.installAndUpgradeHook.enabled .Values.global) | toString) "true" }} +{{- $ds := lookup "apps/v1" "DaemonSet" (include "spire-agent.namespace" .) (include "spire-agent.fullname" .) }} +{{- if and $ds (not (hasKey $ds.metadata.labels "app.kubernetes.io/component")) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "spire-agent.serviceAccountName" . }}-pre-upgrade + namespace: {{ include "spire-agent.namespace" . }} + labels: + {{- include "spire-agent.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "spire-agent.fullname" . }}-pre-upgrade + namespace: {{ include "spire-agent.namespace" . }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +rules: + - apiGroups: ["apps"] + resources: ["daemonsets"] + resourceNames: [{{ include "spire-agent.fullname" . | quote }}] + verbs: ["get", "delete"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "spire-agent.fullname" . }}-pre-upgrade + namespace: {{ include "spire-agent.namespace" . }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +subjects: + - kind: ServiceAccount + name: {{ include "spire-agent.serviceAccountName" . }}-pre-upgrade + namespace: {{ include "spire-agent.namespace" . }} +roleRef: + kind: Role + name: {{ include "spire-agent.fullname" . }}-pre-upgrade + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "spire-agent.fullname" . }}-pre-upgrade + namespace: {{ include "spire-agent.namespace" . }} + labels: + {{- include "spire-agent.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +spec: + template: + metadata: + name: {{ include "spire-agent.fullname" . }}-pre-upgrade + spec: + restartPolicy: Never + serviceAccountName: {{ include "spire-agent.serviceAccountName" . }}-pre-upgrade + securityContext: + {{- include "spire-lib.podsecuritycontext" . | nindent 8 }} + containers: + - name: pre-upgrade + securityContext: + {{- include "spire-lib.securitycontext" . | nindent 10 }} + image: {{ template "spire-lib.kubectl-image" (dict "appVersion" $.Chart.AppVersion "image" .Values.tools.kubectl.image "global" .Values.global "KubeVersion" .Capabilities.KubeVersion.Version) }} + args: + - delete + - daemonset + - {{ include "spire-agent.fullname" . }} + - -n + - {{ include "spire-agent.namespace" . }} +{{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-agent/values.yaml b/charts/spire/charts/spire-agent/values.yaml index b0ddd5bf1..ea10d1244 100644 --- a/charts/spire/charts/spire-agent/values.yaml +++ b/charts/spire/charts/spire-agent/values.yaml @@ -150,7 +150,7 @@ waitForIt: registry: cgr.dev repository: chainguard/wait-for-it pullPolicy: IfNotPresent - tag: latest@sha256:caead414307e81dbdd86d30662fdfe1b999dd4ce8a10fa667dab3438d0eed193 + tag: latest@sha256:1f449e8972f7ffc876cafae20f58e2ff9015141b02cfc637a71ce9a5dddd73ba ## @param waitForIt.resources [object] Resource requests and limits resources: {} @@ -167,7 +167,7 @@ fsGroupFix: registry: cgr.dev repository: chainguard/bash pullPolicy: Always - tag: latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669 + tag: latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2 ## @param fsGroupFix.resources Specify resource needs as per https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -275,7 +275,7 @@ socketAlternate: registry: cgr.dev repository: chainguard/bash pullPolicy: Always - tag: latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669 + tag: latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2 ## @param socketAlternate.resources Specify resource needs as per https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -328,6 +328,37 @@ experimental: ## @param experimental.featureFlags [array] List of developer feature flags featureFlags: [] +## @param agents Configure multiple agent DaemonSets. Useful when you have different node types and nodeAttestors +agents: {} +# default: +# nodeSelector: +# tpm: without +# tpm: +# nodeSelector: +# tpm: with +# nodeAttestor: +# k8sPsat: +# enabled: false +# tpmDirect: +# enabled: true + +installAndUpgradeHook: + ## @param installAndUpgradeHook.enabled Enable Helm hook to autofix common install/upgrade issues (should be disabled when using `helm template`) + enabled: true + +tools: + kubectl: + ## @param tools.kubectl.image.registry The OCI registry to pull the image from + ## @param tools.kubectl.image.repository The repository within the registry + ## @param tools.kubectl.image.pullPolicy The image pull policy + ## @param tools.kubectl.image.tag Overrides the image tag whose default is the chart appVersion + ## + image: + registry: docker.io + repository: rancher/kubectl + pullPolicy: IfNotPresent + tag: "" + sockets: ## @param sockets.hostBasePath Path on which the agent socket is made available when admin.mountOnHost is true hostBasePath: /run/spire/agent/sockets diff --git a/charts/spire/charts/spire-server/README.md b/charts/spire/charts/spire-server/README.md index 64b0e02fc..1c6d8fad8 100644 --- a/charts/spire/charts/spire-server/README.md +++ b/charts/spire/charts/spire-server/README.md @@ -223,7 +223,13 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr | `upstreamAuthority.vault.k8sAuth.k8sAuthRoleName` | Required - Name of the Vault role. The plugin authenticates against the named role | `""` | | `upstreamAuthority.vault.k8sAuth.token.audience` | Intended audience of the PSAT, it must match one of the audiences supported by the Kubernetes API server. If no audience is specified, it defaults to the identifier of API Server. See ['Service Account Documentation'](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection) for more info. | `vault` | | `upstreamAuthority.vault.k8sAuth.token.expiry` | Expiry time in seconds for the token | `7200` | +| `notifier.k8sbundle.enabled` | Enable local k8s bundle uploader | `true` | | `notifier.k8sbundle.namespace` | Namespace to push the bundle into, if blank will default to SPIRE Server namespace | `""` | +| `notifier.externalK8sBundle.enabled` | Enable exernal k8s bundle uploader | `true` | +| `notifier.externalK8sBundle.defaults.namespace` | Namespace to push the bundle into on clusters | `spire-system` | +| `notifier.externalK8sBundle.defaults.configMap` | ConfigMap name to push the bundle into on external clusters | `spire-bundle-upstream` | +| `notifier.externalK8sBundle.defaults.configMapKey` | ConfigMap key to push the bundle into on external clusters | `bundle.crt` | +| `notifier.externalK8sBundle.clusters` | A dictionary of clusters to add with optional overrides. If empty, all clusters defined in kubeConfigs will be used. | `{}` | | `controllerManager.enabled` | Flag to enable controller manager | `false` | | `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` | @@ -296,6 +302,15 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr | `defaultJwtSvidTTL` | TTL for JWT Svids | `1h` | | `nodeAttestor.k8sPsat.enabled` | Enable Psat k8s nodeattestor | `true` | | `nodeAttestor.k8sPsat.serviceAccountAllowList` | Allowed service accounts for Psat nodeattestor | `[]` | +| `nodeAttestor.k8sPsat.audience` | Audience for token validation. If set to [] (empty array), Kubernetes API server audience is used | `[]` | +| `nodeAttestor.k8sPsat.allowedNodeLabelKeys` | Node label keys considered for selectors | `[]` | +| `nodeAttestor.k8sPsat.allowedPodLabelKeys` | Pod label keys considered for selectors | `[]` | +| `nodeAttestor.externalK8sPsat.enabled` | Enable PSAT k8s nodeattestor for external Kubernetes clusters | `true` | +| `nodeAttestor.externalK8sPsat.defaults.serviceAccountAllowList` | Allowed service accounts for PSAT node attestor | `[]` | +| `nodeAttestor.externalK8sPsat.defaults.audience` | Audience for token validation. If it is set to an empty array ([]), Kubernetes API server audience is used | `[]` | +| `nodeAttestor.externalK8sPsat.defaults.allowedNodeLabelKeys` | Node label keys considered for selectors | `[]` | +| `nodeAttestor.externalK8sPsat.defaults.allowedPodLabelKeys` | Pod label keys considered for selectors | `[]` | +| `nodeAttestor.externalK8sPsat.clusters` | A dictionary of clusters to add with optional overrides. If empty, all clusters defined in kubeConfigs will be used. | `{}` | | `nodeAttestor.joinToken.enabled` | Enable the join_token nodeattestor | `false` | | `nodeAttestor.tpmDirect.enabled` | Enable the direct TPM node attestor, a 3rd party plugin by Boxboat. This plugin is experimental. | `false` | | `nodeAttestor.tpmDirect.image.registry` | The OCI registry to pull the image from | `docker.io` | @@ -357,4 +372,5 @@ In order to run Tornjak with simple HTTP Connection only, make sure you don't cr | `tests.bash.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `tests.bash.image.repository` | The repository within the registry | `chainguard/bash` | | `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:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669` | +| `tests.bash.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2` | +| `kubeConfigs` | Manage additional kubeconfig files to talk to external Kubernetes clusters | `{}` | diff --git a/charts/spire/charts/spire-server/templates/configmap.yaml b/charts/spire/charts/spire-server/templates/configmap.yaml index f21198160..8ee8d5e24 100644 --- a/charts/spire/charts/spire-server/templates/configmap.yaml +++ b/charts/spire/charts/spire-server/templates/configmap.yaml @@ -95,16 +95,46 @@ plugins: plugin_data: {{ include "spire-server.datastore-config" . | nindent 10 }} - {{- if or .Values.nodeAttestor.k8sPsat.enabled .Values.nodeAttestor.joinToken.enabled .Values.nodeAttestor.tpmDirect.enabled }} + {{- if or .Values.nodeAttestor.k8sPsat.enabled .Values.nodeAttestor.externalK8sPsat.enabled .Values.nodeAttestor.joinToken.enabled .Values.nodeAttestor.tpmDirect.enabled }} NodeAttestor: - {{- with .Values.nodeAttestor.k8sPsat }} - {{- if eq (.enabled | toString) "true" }} + {{- if or (eq (.Values.nodeAttestor.k8sPsat.enabled | toString) "true") (eq (.Values.nodeAttestor.externalK8sPsat.enabled | toString) "true") }} k8s_psat: plugin_data: clusters: - {{ include "spire-lib.cluster-name" $root }}: + {{- with .Values.nodeAttestor.k8sPsat }} + {{- if eq (.enabled | toString) "true" }} + - {{ include "spire-lib.cluster-name" $root }}: service_account_allow_list: {{ include "spire-server.serviceAccountAllowedList" $root | trim }} - {{- end }} + audience: {{ .audience }} + allowed_node_label_keys: + {{ toYaml .allowedNodeLabelKeys | nindent 14 }} + allowed_pod_label_keys: + {{ toYaml .allowedPodLabelKeys | nindent 14 }} + {{- end }} + {{- end }} + {{- if eq (.Values.nodeAttestor.externalK8sPsat.enabled | toString) "true" }} + {{- $clusters := default .Values.kubeConfigs .Values.nodeAttestor.externalK8sPsat.clusters }} + {{- $clusterDefaults := .Values.nodeAttestor.externalK8sPsat.defaults }} + {{- range $name, $_ := $clusters }} + {{- $clusterSettings := dict }} + {{- if hasKey $root.Values.nodeAttestor.externalK8sPsat.clusters $name }} + {{- $clusterSettings = index $root.Values.nodeAttestor.externalK8sPsat.clusters $name }} + {{- end }} + - {{ $name }}: + {{- if hasKey $clusterSettings "kubeConfigName" }} + kube_config_file: /kubeconfigs/{{ $clusterSettings.kubeConfigName }} + {{- else }} + kube_config_file: /kubeconfigs/{{ $name }} + {{- end }} + service_account_allow_list: + {{ if hasKey $clusterSettings "serviceAccountAllowList" }}{{ toYaml $clusterSettings.serviceAccountAllowList | nindent 14 }}{{ else }}{{ toYaml $clusterDefaults.serviceAccountAllowList | nindent 14 }}{{ end }} + audience: {{ if hasKey $clusterSettings "audience" }}{{ $clusterSettings.audience }}{{ else }}{{ $clusterDefaults.audience }}{{ end }} + allowed_node_label_keys: + {{ if hasKey $clusterSettings "allowedNodeLabelKeys" }}{{ toYaml $clusterSettings.allowedNodeLabelKeys | nindent 14 }}{{ else }}{{ toYaml $clusterDefaults.allowedNodeLabelKeys | nindent 14 }}{{ end }} + allowed_pod_label_keys: + {{ if hasKey $clusterSettings "allowedPodLabelKeys" }}{{ toYaml $clusterSettings.allowedPodLabelKeys | nindent 14 }}{{ else }}{{ toYaml $clusterDefaults.allowedPodLabelKeys | nindent 14 }}{{ end }} + {{- end }} + {{- end }} {{- end }} {{- with .Values.nodeAttestor.joinToken }} {{- if eq (.enabled | toString) "true" }} @@ -175,11 +205,35 @@ plugins: {{- fail (printf "You have to enable exactly one Key Manager. There are %d enabled." $keyManagerUsed) }} {{- end }} + {{- if or .Values.notifier.k8sbundle.enabled .Values.notifier.externalK8sBundle.enabled }} Notifier: k8sbundle: plugin_data: + {{- if eq (.Values.notifier.k8sbundle.enabled | toString) "true" }} namespace: {{ include "spire-server.bundle-namespace" . | quote }} config_map: {{ include "spire-lib.bundle-configmap" . | quote }} + {{- end }} + {{- $clusters := default .Values.kubeConfigs .Values.notifier.externalK8sBundle.clusters }} + {{- if and (eq (.Values.notifier.externalK8sBundle.enabled | toString) "true") (ne (len $clusters) 0) }} + clusters: + - "": + {{- $clusterDefaults := .Values.notifier.externalK8sBundle.defaults }} + {{- range $name, $_ := $clusters }} + {{- $clusterSettings := dict }} + {{- if hasKey $root.Values.notifier.externalK8sBundle.clusters $name }} + {{- $clusterSettings = index $root.Values.notifier.externalK8sBundle.clusters $name }} + {{- end }} + {{- if hasKey $clusterSettings "kubeConfigName" }} + - kube_config_file_path: /kubeconfigs/{{ $clusterSettings.kubeConfigName }} + {{- else }} + - kube_config_file_path: /kubeconfigs/{{ $name }} + {{- end }} + namespace: {{ if hasKey $clusterSettings "namespace" }}{{ $clusterSettings.namespace }}{{ else }}{{ $clusterDefaults.namespace }}{{ end }} + config_map: {{ if hasKey $clusterSettings "configMap" }}{{ $clusterSettings.configMap }}{{ else }}{{ $clusterDefaults.configMap }}{{ end }} + config_map_key: {{ if hasKey $clusterSettings "configMapKey" }}{{ $clusterSettings.configMapKey }}{{ else }}{{ $clusterDefaults.configMapKey }}{{ end }} + {{- end }} + {{- end }} + {{- end }} {{- with .Values.upstreamAuthority.disk }} {{- if eq (.enabled | toString) "true" }} diff --git a/charts/spire/charts/spire-server/templates/kubeconfig-secret.yaml b/charts/spire/charts/spire-server/templates/kubeconfig-secret.yaml new file mode 100644 index 000000000..1a553d760 --- /dev/null +++ b/charts/spire/charts/spire-server/templates/kubeconfig-secret.yaml @@ -0,0 +1,19 @@ +{{- $root := . }} +{{- with .Values.kubeConfigs }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "spire-server.fullname" $root }}-kubeconfigs + namespace: {{ include "spire-server.namespace" $root }} +data: + {{- range $name, $value := . }} + {{- if and (hasKey . "kubeConfig") (hasKey . "kubeConfigBase64") }} + {{- fail "You can not use both kubeConfig and kubeConfigBase64" }} + {{- end }} + {{- if (hasKey . "kubeConfig") }} + {{ $name }}: {{ .kubeConfig | b64enc }} + {{- else }} + {{ $name }}: {{ .kubeConfigBase64 | nospace }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/spire/charts/spire-server/templates/statefulset.yaml b/charts/spire/charts/spire-server/templates/statefulset.yaml index 47f073a2e..2d3f48a7c 100644 --- a/charts/spire/charts/spire-server/templates/statefulset.yaml +++ b/charts/spire/charts/spire-server/templates/statefulset.yaml @@ -181,6 +181,11 @@ spec: - name: spire-data mountPath: /run/spire/data readOnly: false + {{- with .Values.kubeConfigs }} + - name: kubeconfigs + mountPath: /kubeconfigs + readOnly: true + {{- end }} {{- if .Values.nodeAttestor.tpmDirect.enabled }} - name: tpm-direct mountPath: /tpm @@ -362,6 +367,11 @@ spec: emptyDir: {} - name: spire-controller-manager-tmp emptyDir: {} + {{- if gt (len .Values.kubeConfigs) 0 }} + - name: kubeconfigs + secret: + secretName: {{ include "spire-server.fullname" . }}-kubeconfigs + {{- end }} {{- if .Values.nodeAttestor.tpmDirect.enabled }} - name: tpm-direct emptyDir: {} diff --git a/charts/spire/charts/spire-server/values.yaml b/charts/spire/charts/spire-server/values.yaml index 202908244..e32e11ab8 100644 --- a/charts/spire/charts/spire-server/values.yaml +++ b/charts/spire/charts/spire-server/values.yaml @@ -423,8 +423,25 @@ upstreamAuthority: notifier: k8sbundle: + ## @param notifier.k8sbundle.enabled Enable local k8s bundle uploader + enabled: true ## @param notifier.k8sbundle.namespace Namespace to push the bundle into, if blank will default to SPIRE Server namespace namespace: "" + externalK8sBundle: + ## @param notifier.externalK8sBundle.enabled Enable exernal k8s bundle uploader + enabled: true + defaults: + ## @param notifier.externalK8sBundle.defaults.namespace Namespace to push the bundle into on clusters + namespace: "spire-system" + ## @param notifier.externalK8sBundle.defaults.configMap ConfigMap name to push the bundle into on external clusters + configMap: "spire-bundle-upstream" + ## @param notifier.externalK8sBundle.defaults.configMapKey ConfigMap key to push the bundle into on external clusters + configMapKey: "bundle.crt" + ## @param notifier.externalK8sBundle.clusters [object] A dictionary of clusters to add with optional overrides. If empty, all clusters defined in kubeConfigs will be used. + clusters: {} + # clustera: + # namespace: foo + # clusterb: {} controllerManager: ## @param controllerManager.enabled Flag to enable controller manager @@ -700,6 +717,30 @@ nodeAttestor: enabled: true ## @param nodeAttestor.k8sPsat.serviceAccountAllowList [array] Allowed service accounts for Psat nodeattestor serviceAccountAllowList: [] + ## @param nodeAttestor.k8sPsat.audience [array] Audience for token validation. If set to [] (empty array), Kubernetes API server audience is used + audience: ["spire-server"] + ## @param nodeAttestor.k8sPsat.allowedNodeLabelKeys [array] Node label keys considered for selectors + allowedNodeLabelKeys: [] + ## @param nodeAttestor.k8sPsat.allowedPodLabelKeys [array] Pod label keys considered for selectors + allowedPodLabelKeys: [] + externalK8sPsat: + ## @param nodeAttestor.externalK8sPsat.enabled Enable PSAT k8s nodeattestor for external Kubernetes clusters + enabled: true + defaults: + ## @param nodeAttestor.externalK8sPsat.defaults.serviceAccountAllowList [array] Allowed service accounts for PSAT node attestor + serviceAccountAllowList: ["spire-system:spire-agent-upstream"] + ## @param nodeAttestor.externalK8sPsat.defaults.audience [array] Audience for token validation. If it is set to an empty array ([]), Kubernetes API server audience is used + audience: ["spire-server"] + ## @param nodeAttestor.externalK8sPsat.defaults.allowedNodeLabelKeys [array] Node label keys considered for selectors + allowedNodeLabelKeys: [] + ## @param nodeAttestor.externalK8sPsat.defaults.allowedPodLabelKeys [array] Pod label keys considered for selectors + allowedPodLabelKeys: [] + ## @param nodeAttestor.externalK8sPsat.clusters [object] A dictionary of clusters to add with optional overrides. If empty, all clusters defined in kubeConfigs will be used. + clusters: {} + # clustera: + # kubeConfigName: foo + # serviceAccountAllowList: ["other-ns:other-agent"] + # clusterb: {} joinToken: ## @param nodeAttestor.joinToken.enabled Enable the join_token nodeattestor enabled: false @@ -886,4 +927,13 @@ tests: registry: cgr.dev repository: chainguard/bash pullPolicy: IfNotPresent - tag: latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669 + tag: latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2 + +## @param kubeConfigs [object] Manage additional kubeconfig files to talk to external Kubernetes clusters +kubeConfigs: {} +# clustera: +# kubeConfig: | +# xxxxx +# xxxxx +# clusterb: +# kubeConfigBase64: eXl5Cnl5eQo= diff --git a/charts/spire/charts/tornjak-frontend/README.md b/charts/spire/charts/tornjak-frontend/README.md index 94e61eac8..493a69dec 100644 --- a/charts/spire/charts/tornjak-frontend/README.md +++ b/charts/spire/charts/tornjak-frontend/README.md @@ -98,4 +98,4 @@ port forwarding. See the chart NOTES output for more details. | `tests.bash.image.registry` | The OCI registry to pull the image from | `cgr.dev` | | `tests.bash.image.repository` | The repository within the registry | `chainguard/bash` | | `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:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669` | +| `tests.bash.image.tag` | Overrides the image tag whose default is the chart appVersion | `latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2` | diff --git a/charts/spire/charts/tornjak-frontend/values.yaml b/charts/spire/charts/tornjak-frontend/values.yaml index 7e16f9539..67acd5d14 100644 --- a/charts/spire/charts/tornjak-frontend/values.yaml +++ b/charts/spire/charts/tornjak-frontend/values.yaml @@ -154,4 +154,4 @@ tests: registry: cgr.dev repository: chainguard/bash pullPolicy: IfNotPresent - tag: latest@sha256:81f0b434b297453ff101de0b5f4f5cd8d4af1c015a1d34162e9ae9a4a9f38669 + tag: latest@sha256:d69268f206bc7914c25f7377309a73406517678458ebccec0e6bfab7b9b7e9d2 diff --git a/examples/external-mysql/README.md b/examples/external-mysql/README.md index 8a6864ccf..9c9d96805 100644 --- a/examples/external-mysql/README.md +++ b/examples/external-mysql/README.md @@ -10,13 +10,11 @@ If manually deploying for testing, you can safely put the password into an envir source ../bin/readpw.sh ``` -Next, edit values.yaml with your settings. Check it into your git repo if using one. +Follow the instructions as described at https://artifacthub.io/packages/helm/spiffe/spire, and copy in the settings from +examples/external-mysql/values.yaml into your values file. -Then, deploy the chart pointing at your mysql instance like so: +You can add the password at install runtime like so: ```shell -helm upgrade --install --namespace spire-server spire charts/spire -f examples/external-mysql/values.yaml --set "spire-server.dataStore.sql.password=${DBPW}" +helm upgrade --install --namespace spire-mgmt spire spire -f your-values.yaml --set "spire-server.dataStore.sql.password=${DBPW}" --repo https://spiffe.github.io/helm-charts-hardened/ ``` - -See the [production example](../production) for production recommendations. -See [values.yaml](./values.yaml) for more details on the chart configurations to achieve this setup. diff --git a/examples/external-mysql/run-tests.sh b/examples/external-mysql/run-tests.sh index 0f41ea87c..6f3bd7a3a 100755 --- a/examples/external-mysql/run-tests.sh +++ b/examples/external-mysql/run-tests.sh @@ -54,6 +54,6 @@ helm upgrade --install mysql mysql --version "$VERSION_MYSQL" --repo "$HELM_REPO --wait helm upgrade --install --namespace "spire-server" \ - --values "${SCRIPTPATH}/values.yaml,${SCRIPTPATH}/../production/values.yaml,${SCRIPTPATH}/../production/values-node-pod-antiaffinity.yaml,${SCRIPTPATH}/../production/example-your-values.yaml" \ + --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/external-postgresql/README.md b/examples/external-postgresql/README.md index d4710fbee..3e4edf436 100644 --- a/examples/external-postgresql/README.md +++ b/examples/external-postgresql/README.md @@ -10,14 +10,12 @@ If manually deploying for testing, you can safely put the password into an envir source ../bin/readpw.sh ``` -Next, edit values.yaml with your settings. Check it into your git repo if using one. +Follow the instructions as described at https://artifacthub.io/packages/helm/spiffe/spire, and copy in the settings from +examples/external-postgresql/values.yaml into your values file. -Then, deploy the chart pointing at your postgresql instance like so: +You can add the password at install runtime like so: ```shell -helm upgrade --install --namespace spire-server spire charts/spire -f examples/external-postgresql/values.yaml --set "spire-server.dataStore.sql.password=${DBPW}" +helm upgrade --install --namespace spire-mgmt spire spire -f your-values.yaml --set "spire-server.dataStore.sql.password=${DBPW}" --repo https://spiffe.github.io/helm-charts-hardened/ ``` - -See the [production example](../production) for production recommendations. -See [values.yaml](./values.yaml) for more details on the chart configurations to achieve this setup. diff --git a/examples/external-postgresql/run-tests.sh b/examples/external-postgresql/run-tests.sh index 3a93f68ef..fe9ba70dd 100755 --- a/examples/external-postgresql/run-tests.sh +++ b/examples/external-postgresql/run-tests.sh @@ -50,10 +50,10 @@ kubectl label namespace spire-server pod-security.kubernetes.io/enforce=restrict helm upgrade --install postgresql postgresql --version "$VERSION_POSTGRESQL" --repo "$HELM_REPO_POSTGRESQL" \ --namespace spire-server \ - --values "${DEPS}/postgresql.yaml,${SCRIPTPATH}/../production/values.yaml,${SCRIPTPATH}/../production/values-node-pod-antiaffinity.yaml" \ + --values "${DEPS}/postgresql.yaml" \ --wait helm upgrade --install --namespace "spire-server" \ - --values "${SCRIPTPATH}/values.yaml,${SCRIPTPATH}/../production/values.yaml,${SCRIPTPATH}/../production/values-node-pod-antiaffinity.yaml,${SCRIPTPATH}/../production/example-your-values.yaml" \ + --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/production/values-node-pod-antiaffinity.yaml b/examples/misc/values-node-pod-antiaffinity.yaml similarity index 100% rename from examples/production/values-node-pod-antiaffinity.yaml rename to examples/misc/values-node-pod-antiaffinity.yaml diff --git a/examples/nested/run-tests.sh b/examples/nested/run-tests.sh index 8fd5fe43e..ee0dbe549 100755 --- a/examples/nested/run-tests.sh +++ b/examples/nested/run-tests.sh @@ -55,7 +55,7 @@ helm upgrade --install --create-namespace spire charts/spire \ --values "${DEPS}/spire-root-server-values.yaml" \ --wait -helm upgrade --install --create-namespace --namespace spire-server --values "${SCRIPTPATH}/values.yaml,${SCRIPTPATH}/../production/values.yaml,${SCRIPTPATH}/../production/values-node-pod-antiaffinity.yaml,${SCRIPTPATH}/../production/example-your-values.yaml" \ +helm upgrade --install --create-namespace --namespace spire-server --values "${COMMON_TEST_YOUR_VALUES},${SCRIPTPATH}/values.yaml,${SCRIPTPATH}/../misc/values-node-pod-antiaffinity.yaml" \ --wait spire charts/spire helm test --namespace spire-server spire diff --git a/examples/production/README.md b/examples/production/README.md deleted file mode 100644 index e2c04e310..000000000 --- a/examples/production/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# Recommended production setup - -To install Spire with the least privileges possible we deploy spire across 2 namespaces. - -```shell -kubectl create namespace "spire-system" -kubectl label namespace "spire-system" pod-security.kubernetes.io/enforce=privileged -kubectl create namespace "spire-server" -kubectl label namespace "spire-server" pod-security.kubernetes.io/enforce=restricted -``` - -Update the `example-your-values.yaml` file with your values, then: - -```shell -helm upgrade --install --namespace spire-server spire charts/spire \ - -f examples/production/values.yaml -f examples/production/example-your-values.yaml --render-subchart-notes -``` - -If your using ingress-nginx and want to expose the spiffe oidc discovery provider outside the -cluster, add the following to the end of the helm upgrade example: - -```shell --f examples/production/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml -``` - -If you want to expose your spire-server outside of Kubernetes and are using ingress-nginx, add following values file when running `helm template/install/upgrade`. - -```shell --f examples/production/values-expose-spire-server-ingress-nginx.yaml -``` - -For example: - -```shell -helm upgrade --install --namespace spire-server spire charts/spire -f examples/production/values.yaml -f examples/production/values-expose-spire-server-ingress-nginx.yaml -``` - -If you want to expose your federation endpoint outside of Kubernetes and are using ingress-nginx -you have two options as described here: -[github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Federation.md#52-endpoint-profiles](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Federation.md#52-endpoint-profiles) - -If you chose profile https_web, use: - -```shell --f examples/production/values-expose-federation-https-web-ingress-nginx.yaml -``` - -For example: - -```shell -helm upgrade --install --namespace spire-server spire charts/spire -f examples/production/values.yaml -f examples/production/values-expose-federation-https-web-ingress-nginx.yaml -``` - -If you chose profile https_spiffe, use: - -```shell --f examples/production/values-expose-federation-https-spiffe-ingress-nginx.yaml -``` - -For example: - -```shell -helm upgrade --install --namespace spire-server spire charts/spire -f examples/production/values.yaml -f examples/production/values-expose-federation-https-spiffe-ingress-nginx.yaml -``` - -See [values.yaml](./values.yaml) for more details on the chart configurations to achieve this setup. diff --git a/examples/production/example-your-values.yaml b/examples/production/example-your-values.yaml deleted file mode 100644 index 7c3a830e9..000000000 --- a/examples/production/example-your-values.yaml +++ /dev/null @@ -1,22 +0,0 @@ -global: - spire: - clusterName: production - trustDomain: production.other - -spire-server: - ca_subject: - country: US - organization: Production - common_name: production.other - -# ingress: -# host: spire-server -# federation: -# ingress: -# host: spire-server-federation -# tlsSecret: tls-cert - -# spiffe-oidc-discovery-provider: -# ingress: -# host: oidc-discovery -# tlsSecret: tls-cert diff --git a/examples/production/values.yaml b/examples/production/values.yaml deleted file mode 100644 index c5ce8bd45..000000000 --- a/examples/production/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -global: - spire: - recommendations: - enabled: true diff --git a/examples/tpm-direct/different-nodes.yaml b/examples/tpm-direct/different-nodes.yaml new file mode 100644 index 000000000..86d913ee0 --- /dev/null +++ b/examples/tpm-direct/different-nodes.yaml @@ -0,0 +1,22 @@ +spire-agent: + agents: + default: + nodeSelector: + tpm: without + tpm: + nodeSelector: + tpm: with + nodeAttestor: + k8sPsat: + enabled: false + tpmDirect: + enabled: true + +spire-server: + controllerManager: + # K8s labels have a 63 character limit. TPM hashes are 64 chars. So you need to label the node with two labels with half of the tpm's hash each. The 'node-restriction.kubernetes.io/' prefix is so that the + # nodes can't update the hash themselves, an important security constraint. + parentIDTemplate: 'spiffe://{{ .TrustDomain }}/spire/agent/{{if index .NodeMeta.Labels "node-restriction.kubernetes.io/tpm-pubhash"}}tpm/{{ index .NodeMeta.Labels "node-restriction.kubernetes.io/tpm-pubhash" }}{{ index .NodeMeta.Labels "node-restriction.kubernetes.io/tpm-pubhash2" }}{{ else }}spire/agent/k8s_psat/{{ .ClusterName }}/{{ .NodeMeta.UID }}{{ end }}' + nodeAttestor: + tpmDirect: + enabled: true diff --git a/examples/tpm-direct/same-nodes.yaml b/examples/tpm-direct/same-nodes.yaml new file mode 100644 index 000000000..ab53a82c3 --- /dev/null +++ b/examples/tpm-direct/same-nodes.yaml @@ -0,0 +1,15 @@ +spire-agent: + nodeAttestor: + k8sPsat: + enabled: false + tpmDirect: + enabled: true + +spire-server: + controllerManager: + # K8s labels have a 63 character limit. TPM hashes are 64 chars. So you need to label the node with two labels with half of the tpm's hash each. The 'node-restriction.kubernetes.io/' prefix is so that the + # nodes can't update the hash themselves, an important security constraint. + parentIDTemplate: 'spiffe://{{ .TrustDomain }}/spire/agent/tpm/{{ index .NodeMeta.Labels "node-restriction.kubernetes.io/tpm-pubhash" }}{{ index .NodeMeta.Labels "node-restriction.kubernetes.io/tpm-pubhash2" }}' + nodeAttestor: + tpmDirect: + enabled: true diff --git a/tests/go.mod b/tests/go.mod index 5ce11f225..9cb21c328 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -5,9 +5,9 @@ go 1.21 toolchain go1.21.5 require ( - github.com/onsi/ginkgo/v2 v2.16.0 - github.com/onsi/gomega v1.31.1 - helm.sh/helm/v3 v3.14.2 + github.com/onsi/ginkgo/v2 v2.17.0 + github.com/onsi/gomega v1.32.0 + helm.sh/helm/v3 v3.14.3 ) require ( @@ -56,7 +56,7 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.17.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index e034fa853..245df192e 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -90,10 +90,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/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/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM= -github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= -github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= -github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= +github.com/onsi/ginkgo/v2 v2.17.0 h1:kdnunFXpBjbzN56hcJHrXZ8M+LOkenKA7NnBzTNigTI= +github.com/onsi/ginkgo/v2 v2.17.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -196,8 +196,8 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -212,8 +212,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= -helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= +helm.sh/helm/v3 v3.14.3 h1:HmvRJlwyyt9HjgmAuxHbHv3PhMz9ir/XNWHyXfmnOP4= +helm.sh/helm/v3 v3.14.3/go.mod h1:v6myVbyseSBJTzhmeE39UcPLNv6cQK6qss3dvgAySaE= k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= diff --git a/examples/production/run-tests.sh b/tests/integration/production/run-tests.sh similarity index 95% rename from examples/production/run-tests.sh rename to tests/integration/production/run-tests.sh index bd67728c7..8cf3adb99 100755 --- a/examples/production/run-tests.sh +++ b/tests/integration/production/run-tests.sh @@ -7,11 +7,11 @@ UPGRADE_REPO=https://spiffe.github.io/helm-charts-hardened SCRIPT="$(readlink -f "$0")" SCRIPTPATH="$(dirname "${SCRIPT}")" -TESTDIR="${SCRIPTPATH}/../../.github/tests" +TESTDIR="${SCRIPTPATH}/../../../.github/tests" DEPS="${TESTDIR}/dependencies" # shellcheck source=/dev/null -source "${SCRIPTPATH}/../../.github/scripts/parse-versions.sh" +source "${SCRIPTPATH}/../../../.github/scripts/parse-versions.sh" # shellcheck source=/dev/null source "${TESTDIR}/common.sh" @@ -122,7 +122,7 @@ install_and_test() { # shellcheck disable=SC2086 "${helm_install[@]}" spire "$1" \ --namespace "${ns}" \ - --values "${SCRIPTPATH}/values.yaml" \ + --values "${COMMON_TEST_YOUR_VALUES}" \ --values "${SCRIPTPATH}/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml" \ --values "${SCRIPTPATH}/values-expose-spire-server-ingress-nginx.yaml" \ --values "${SCRIPTPATH}/values-expose-federation-https-web-ingress-nginx.yaml" \ @@ -130,8 +130,6 @@ install_and_test() { --set spiffe-oidc-discovery-provider.tests.tls.customCA=tls-cert,spire-server.tests.tls.customCA=tls-cert \ --set spire-agent.server.address=spire-server.production.other,spire-agent.server.port=443 \ --set spire-server.federation.ingress.tlsSecret=tls-cert,spiffe-oidc-discovery-provider.ingress.tlsSecret=tls-cert \ - --values "${SCRIPTPATH}/example-your-values.yaml" \ - $2 \ --wait helm test --namespace "${ns}" spire diff --git a/examples/production/values-expose-federation-https-spiffe-ingress-nginx.yaml b/tests/integration/production/values-expose-federation-https-spiffe-ingress-nginx.yaml similarity index 100% rename from examples/production/values-expose-federation-https-spiffe-ingress-nginx.yaml rename to tests/integration/production/values-expose-federation-https-spiffe-ingress-nginx.yaml diff --git a/examples/production/values-expose-federation-https-web-ingress-nginx.yaml b/tests/integration/production/values-expose-federation-https-web-ingress-nginx.yaml similarity index 100% rename from examples/production/values-expose-federation-https-web-ingress-nginx.yaml rename to tests/integration/production/values-expose-federation-https-web-ingress-nginx.yaml diff --git a/examples/production/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml b/tests/integration/production/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml similarity index 100% rename from examples/production/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml rename to tests/integration/production/values-expose-spiffe-oidc-discovery-provider-ingress-nginx.yaml diff --git a/examples/production/values-expose-spire-server-ingress-nginx.yaml b/tests/integration/production/values-expose-spire-server-ingress-nginx.yaml similarity index 100% rename from examples/production/values-expose-spire-server-ingress-nginx.yaml rename to tests/integration/production/values-expose-spire-server-ingress-nginx.yaml diff --git a/tests/integration/psat/kind-config.yaml b/tests/integration/psat/kind-config.yaml new file mode 100644 index 000000000..d85992ac3 --- /dev/null +++ b/tests/integration/psat/kind-config.yaml @@ -0,0 +1,7 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +networking: + apiServerAddress: "172.17.0.1" + apiServerPort: 7443 + podSubnet: "10.245.0.0/16" + serviceSubnet: "10.97.0.0/12" diff --git a/tests/integration/psat/run-tests.sh b/tests/integration/psat/run-tests.sh new file mode 100755 index 000000000..6b7785aec --- /dev/null +++ b/tests/integration/psat/run-tests.sh @@ -0,0 +1,68 @@ +#!/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-root-server + print_spire_workload_status spire-server spire-system + + if [[ "$1" -ne 0 ]]; then + get_namespace_details spire-root-server + get_namespace_details spire-server spire-system + fi + + if [ "${CLEANUP}" -eq 1 ]; then + helm uninstall --namespace spire-server spire 2>/dev/null || true + kubectl delete ns spire-server 2>/dev/null || true + kubectl delete ns spire-system 2>/dev/null || true + + helm uninstall --namespace mysql spire-root-server 2>/dev/null || true + kubectl delete ns spire-root-server 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 --create-namespace spire charts/spire \ + --namespace spire-root-server \ + --values "${DEPS}/spire-root-server-values.yaml" \ + --wait + +kind create cluster --name other --kubeconfig "${SCRIPTPATH}/kubeconfig" --config "${SCRIPTPATH}/kind-config.yaml" +md5sum "${SCRIPTPATH}/kubeconfig" +wc -l "${SCRIPTPATH}/kubeconfig" +KCB64="$(base64 < "${SCRIPTPATH}/kubeconfig" | tr '\n' ' ' | sed 's/ //g')" +kubectl --kubeconfig "${SCRIPTPATH}/kubeconfig" create namespace spire-system +kubectl --kubeconfig "${SCRIPTPATH}/kubeconfig" create configmap -n spire-system spire-bundle-upstream + +helm upgrade --install --create-namespace --namespace spire-server --values "${SCRIPTPATH}/values.yaml" \ + --wait spire charts/spire --set "spire-server.kubeConfigs.other.kubeConfigBase64=$KCB64" +helm test --namespace spire-server spire +kubectl --kubeconfig "${SCRIPTPATH}/kubeconfig" get configmap -n spire-system spire-bundle-upstream diff --git a/tests/integration/psat/values.yaml b/tests/integration/psat/values.yaml new file mode 100644 index 000000000..fbb7b55e8 --- /dev/null +++ b/tests/integration/psat/values.yaml @@ -0,0 +1,12 @@ +global: + spire: + recommendations: + enabled: true + clusterName: production + trustDomain: production.other + +spire-server: + ca_subject: + country: US + organization: Production + common_name: production.other