From 8832da39b4549c942785255730fe030fad4d81ef Mon Sep 17 00:00:00 2001 From: nweisenauer <137267159+nweisenauer-sap@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:23:01 +0200 Subject: [PATCH] Protects SPIRE Agent's Chart Against YAML Template Injection (#450) * protects agent's chart against template injection Signed-off-by: Nico Weisenauer <137267159+nweisenauer-sap@users.noreply.github.com> * removes unnecessary braces and whitespace Signed-off-by: Nico Weisenauer <137267159+nweisenauer-sap@users.noreply.github.com> * Removes int type validation via cast Signed-off-by: Nico Weisenauer <137267159+nweisenauer-sap@users.noreply.github.com> --------- Signed-off-by: Nico Weisenauer <137267159+nweisenauer-sap@users.noreply.github.com> --- .../charts/spire-agent/templates/_helpers.tpl | 8 +-- .../spire-agent/templates/configmap.yaml | 14 ++--- .../spire-agent/templates/daemonset.yaml | 58 +++++++++++-------- .../spire-agent/templates/podmonitor.yaml | 4 +- .../charts/spire-agent/templates/roles.yaml | 10 ++-- .../templates/scc-spire-agent.yaml | 4 +- .../spire-agent/templates/serviceaccount.yaml | 4 +- .../charts/spire-lib/templates/_helpers.tpl | 12 ++-- 8 files changed, 61 insertions(+), 53 deletions(-) diff --git a/charts/spire/charts/spire-agent/templates/_helpers.tpl b/charts/spire/charts/spire-agent/templates/_helpers.tpl index fe77147..34e6b08 100644 --- a/charts/spire/charts/spire-agent/templates/_helpers.tpl +++ b/charts/spire/charts/spire-agent/templates/_helpers.tpl @@ -75,20 +75,20 @@ Create chart name and version as used by the chart label. Common labels */}} {{- define "spire-agent.labels" -}} -helm.sh/chart: {{ include "spire-agent.chart" . }} +helm.sh/chart: {{ include "spire-agent.chart" . | quote }} {{ include "spire-agent.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/managed-by: {{ .Release.Service | quote }} {{- end }} {{/* Selector labels */}} {{- define "spire-agent.selectorLabels" -}} -app.kubernetes.io/name: {{ include "spire-agent.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/name: {{ include "spire-agent.name" . | quote }} +app.kubernetes.io/instance: {{ .Release.Name | quote }} {{- end }} {{/* diff --git a/charts/spire/charts/spire-agent/templates/configmap.yaml b/charts/spire/charts/spire-agent/templates/configmap.yaml index d659ce7..d46c6b7 100644 --- a/charts/spire/charts/spire-agent/templates/configmap.yaml +++ b/charts/spire/charts/spire-agent/templates/configmap.yaml @@ -53,7 +53,7 @@ agent: default_svid_name: {{ .Values.sds.defaultSvidName | quote }} default_bundle_name: {{ .Values.sds.defaultBundleName | quote }} default_all_bundles_name: {{ .Values.sds.defaultAllBundlesName | quote }} - disable_spiffe_cert_validation: {{ .Values.sds.disableSpiffeCertValidation }} + disable_spiffe_cert_validation: {{ eq .Values.sds.disableSpiffeCertValidation true }} {{- end }} {{- with .Values.experimental }} @@ -97,7 +97,7 @@ plugins: {{- if eq (.enabled | toString) "true" }} tpm: plugin_cmd: "/tpm/tpm_attestor_agent" - plugin_checksum: {{ .plugin.checksum }} + plugin_checksum: {{ .plugin.checksum | quote }} plugin_data: {} {{- $nodeAttestorUsed = add1 $nodeAttestorUsed }} {{- end }} @@ -126,9 +126,9 @@ plugins: kubelet_ca_path: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt {{- end }} skip_kubelet_verification: {{ eq .Values.workloadAttestors.k8s.verification.type "skip" }} - disable_container_selectors: {{ .Values.workloadAttestors.k8s.disableContainerSelectors }} - use_new_container_locator: {{ .Values.workloadAttestors.k8s.useNewContainerLocator }} - verbose_container_locator_logs: {{ .Values.workloadAttestors.k8s.verboseContainerLocatorLogs }} + disable_container_selectors: {{ eq .Values.workloadAttestors.k8s.disableContainerSelectors true}} + use_new_container_locator: {{ eq .Values.workloadAttestors.k8s.useNewContainerLocator true }} + verbose_container_locator_logs: {{ eq .Values.workloadAttestors.k8s.verboseContainerLocatorLogs true }} {{- if eq (include "spire-agent.connect-by-hostname" .) "true" }} node_name_env: "MY_NODE_NAME" {{- end }} @@ -168,8 +168,8 @@ telemetry: apiVersion: v1 kind: ConfigMap metadata: - name: {{ include "spire-agent.fullname" . }}{{ $nameSuffix }} - namespace: {{ include "spire-agent.namespace" . }} + name: {{ printf "%s%s" (include "spire-agent.fullname" .) $nameSuffix | quote }} + namespace: {{ include "spire-agent.namespace" . | quote }} {{- with .Values.configMap.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/charts/spire/charts/spire-agent/templates/daemonset.yaml b/charts/spire/charts/spire-agent/templates/daemonset.yaml index 3bec7b0..c242127 100644 --- a/charts/spire/charts/spire-agent/templates/daemonset.yaml +++ b/charts/spire/charts/spire-agent/templates/daemonset.yaml @@ -22,16 +22,16 @@ apiVersion: apps/v1 kind: DaemonSet metadata: - name: {{ include "spire-agent.fullname" . }}{{ $nameSuffix }} - namespace: {{ include "spire-agent.namespace" . }} + name: {{ printf "%s%s" (include "spire-agent.fullname" .) $nameSuffix | quote }} + namespace: {{ include "spire-agent.namespace" . | quote}} labels: {{- include "spire-agent.labels" . | nindent 4 }} - app.kubernetes.io/component: {{ $name }} + app.kubernetes.io/component: {{ $name | quote }} spec: selector: matchLabels: {{- include "spire-agent.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: {{ $name }} + app.kubernetes.io/component: {{ $name | quote }} {{- with .Values.updateStrategy }} updateStrategy: {{- if not (has .type (list "RollingUpdate" "OnDelete")) }} @@ -47,13 +47,13 @@ spec: metadata: annotations: kubectl.kubernetes.io/default-container: spire-agent - checksum/config: {{ $configSum }} + checksum/config: {{ $configSum | quote }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "spire-agent.selectorLabels" . | nindent 8 }} - app.kubernetes.io/component: {{ $name }} + app.kubernetes.io/component: {{ $name | quote }} {{- with .Values.podLabels }} {{- toYaml . | nindent 8 }} {{- end }} @@ -65,7 +65,7 @@ spec: hostPID: true hostNetwork: true dnsPolicy: ClusterFirstWithHostNet - serviceAccountName: {{ include "spire-agent.serviceAccountName" . }} + serviceAccountName: {{ include "spire-agent.serviceAccountName" . | quote }} securityContext: {{- toYaml $podSecurityContext | nindent 8 }} {{- include "spire-lib.default_node_priority_class_name" . | nindent 6 }} @@ -79,17 +79,17 @@ spec: securityContext: {{- $mainSecurityContext | toYaml | nindent 12 }} image: {{ template "spire-lib.image" (dict "image" .Values.hostCert.image "global" .Values.global) }} - imagePullPolicy: {{ .Values.hostCert.image.pullPolicy }} + imagePullPolicy: {{ .Values.hostCert.image.pullPolicy | quote }} command: ["bash", "-xc"] args: - | {{- if ne .Values.workloadAttestors.k8s.verification.hostCert.fileName "" }} - openssl x509 -in "{{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }}/{{ .Values.workloadAttestors.k8s.verification.hostCert.fileName }}" -out /hostCert/kubelet.crt + openssl x509 -in {{ printf "%s/%s" .Values.workloadAttestors.k8s.verification.hostCert.basePath .Values.workloadAttestors.k8s.verification.hostCert.fileName | quote }} -out /hostCert/kubelet.crt {{- else }} if [ -f "{{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }}/kubelet-server-current.pem" ]; then - openssl x509 -in "{{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }}/kubelet-server-current.pem" -out /hostCert/kubelet.crt + openssl x509 -in {{ printf "%s/kubelet-server-current.pem" .Values.workloadAttestors.k8s.verification.hostCert.basePath | quote }} -out /hostCert/kubelet.crt elif [ -f "{{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }}/kubelet.crt" ]; then - openssl x509 -in "{{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }}/kubelet.crt" -out /hostCert/kubelet.crt + openssl x509 -in {{ printf "%s/kubelet.crt" .Values.workloadAttestors.k8s.verification.hostCert.basePath | quote }} -out /hostCert/kubelet.crt else {{- if eq .Values.workloadAttestors.k8s.verification.type "auto" }} {{- if $cbh }} @@ -150,7 +150,7 @@ spec: readOnly: true - name: kmsg mountPath: /dev/kmsg - imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.pubHash.image.pullPolicy }} + imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.pubHash.image.pullPolicy | quote }} {{- end }} - name: init-tpm-direct securityContext: @@ -161,16 +161,16 @@ spec: - -ec - | # SPIRE must be able to fork the plugin directly within its container. Copy the plugin into a volume that can be mounted where SPIRE can execute it. - cp -a {{ .Values.nodeAttestor.tpmDirect.plugin.path }} /tpm/tpm_attestor_agent + cp -a {{ .Values.nodeAttestor.tpmDirect.plugin.path | quote }} /tpm/tpm_attestor_agent volumeMounts: - name: tpm-direct mountPath: /tpm - imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.plugin.image.pullPolicy }} + imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.plugin.image.pullPolicy | quote }} {{- end }} {{- if gt (len $socketAlternateNames) 0 }} - name: ensure-alternate-names image: {{ template "spire-lib.image" (dict "image" .Values.socketAlternate.image "global" .Values.global) }} - imagePullPolicy: {{ .Values.socketAlternate.image.pullPolicy }} + imagePullPolicy: {{ .Values.socketAlternate.image.pullPolicy | quote }} command: ["bash", "-xc"] {{- /* 1. Look for symlinks pointing at the wrong place and remove them. 2. Make symlinks that don't exist. 3. If new socket is pointing at an existing symlink, remove old symlink. */}} args: @@ -178,7 +178,7 @@ spec: cd {{ $socketPath | dir }} {{- range $socketAlternateNames }} L=`readlink {{ . }}` - [ "x$L" != "x{{ $socketPath | base}}" ] && rm -f {{ . }} + [ "x$L" != "x{{ $socketPath | base }}" ] && rm -f {{ . }} [ ! -L {{ . }} ] && ln -s {{ $socketPath | base }} {{ . }} {{- end }} [ -L {{ $socketPath | base }} ] && rm -f {{ $socketPath | base }} @@ -195,12 +195,12 @@ spec: {{- if gt (int (dig "fsGroup" 0 $podSecurityContext)) 0 }} - name: fsgroupfix image: {{ template "spire-lib.image" (dict "image" .Values.fsGroupFix.image "global" .Values.global) }} - imagePullPolicy: {{ .Values.fsGroupFix.image.pullPolicy }} + imagePullPolicy: {{ .Values.fsGroupFix.image.pullPolicy | quote }} command: ["bash", "-c"] args: - | - chown -R {{ $podSecurityContext.runAsUser }}:{{ $podSecurityContext.fsGroup }} {{ $socketPath | dir }} /tmp/spire-agent/private - chown -R {{ $podSecurityContext.runAsUser }}:{{ $podSecurityContext.fsGroup }} /var/lib/spire + chown -R {{ printf "%v:%v" $podSecurityContext.runAsUser $podSecurityContext.fsGroup | quote }} {{ $socketPath | dir }} /tmp/spire-agent/private + chown -R {{ printf "%v:%v" $podSecurityContext.runAsUser $podSecurityContext.fsGroup | quote }} /var/lib/spire resources: {{- toYaml .Values.fsGroupFix.resources | nindent 12 }} volumeMounts: @@ -218,9 +218,9 @@ spec: {{- toYaml .Values.initContainers | nindent 8 }} {{- end }} containers: - - name: {{ .Chart.Name }} + - name: {{ .Chart.Name | quote }} image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.image "global" .Values.global) }} - imagePullPolicy: {{ .Values.image.pullPolicy }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} args: ["-config", "/opt/spire/conf/agent/agent.conf"] securityContext: {{- $mainSecurityContext | toYaml | nindent 12 }} @@ -314,7 +314,11 @@ spec: {{- if .Values.sockets.admin.mountOnHost }} - name: spire-agent-admin-socket-dir hostPath: - path: {{ .Values.sockets.hostBasePath }}/{{ if .Values.upstream }}upstream.csi.spiffe.io{{ else }}csi.spiffe.io{{ end }}/admin + {{- if .Values.upstream }} + path: {{ printf "%s/upstream.csi.spiffe.io/admin" .Values.sockets.hostBasePath | quote }} + {{- else }} + path: {{ printf "%s/csi.spiffe.io/admin" .Values.sockets.hostBasePath | quote }} + {{- end }} type: DirectoryOrCreate {{- else }} - name: spire-agent-admin-socket-dir @@ -323,7 +327,11 @@ spec: {{- if eq .Values.persistence.type "hostPath" }} - name: spire-agent-persistence hostPath: - path: {{ .Values.persistence.hostPath }}/{{ if .Values.upstream }}upstream.csi.spiffe.io{{ else }}csi.spiffe.io{{ end }} + {{- if .Values.upstream }} + path: {{ printf "%s/upstream.csi.spiffe.io" .Values.persistence.hostPath | quote }} + {{- else }} + path: {{ printf "%s/csi.spiffe.io" .Values.persistence.hostPath | quote }} + {{- end }} type: DirectoryOrCreate {{- else }} - name: spire-agent-persistence @@ -332,7 +340,7 @@ spec: {{- if eq (len .Values.trustBundleURL) 0 }} - name: spire-bundle configMap: - name: {{ include "spire-lib.bundle-configmap" . }}{{ $nameSuffix }} + name: {{ printf "%s%s" (include "spire-lib.bundle-configmap" .) $nameSuffix | quote }} {{- end }} {{- if .Values.nodeAttestor.tpmDirect.enabled }} - name: tpm-direct @@ -364,7 +372,7 @@ spec: emptyDir: {} - name: host-cert hostPath: - path: {{ .Values.workloadAttestors.k8s.verification.hostCert.basePath }} + path: {{ .Values.workloadAttestors.k8s.verification.hostCert.basePath | quote }} {{- end }} {{- if gt (len .Values.extraVolumes) 0 }} {{- toYaml .Values.extraVolumes | nindent 8 }} diff --git a/charts/spire/charts/spire-agent/templates/podmonitor.yaml b/charts/spire/charts/spire-agent/templates/podmonitor.yaml index 409bfb3..a800128 100644 --- a/charts/spire/charts/spire-agent/templates/podmonitor.yaml +++ b/charts/spire/charts/spire-agent/templates/podmonitor.yaml @@ -5,7 +5,7 @@ apiVersion: monitoring.coreos.com/v1 kind: PodMonitor metadata: name: {{ include "spire-agent.fullname" . }} - namespace: {{ $namespace }} + namespace: {{ $namespace | quote }} labels: {{- include "spire-agent.labels" . | nindent 4 }} {{- if ne (len (dig "telemetry" "prometheus" "podMonitor" "labels" (dict) .Values.global)) 0 }} @@ -22,6 +22,6 @@ spec: - port: prom {{- if ne $namespace $podNamespace }} namespaceSelector: - kubernetes.io/metadata.name: {{ $podNamespace }} + kubernetes.io/metadata.name: {{ $podNamespace | quote }} {{- end }} {{- end }} diff --git a/charts/spire/charts/spire-agent/templates/roles.yaml b/charts/spire/charts/spire-agent/templates/roles.yaml index e6878a2..f4df1ce 100644 --- a/charts/spire/charts/spire-agent/templates/roles.yaml +++ b/charts/spire/charts/spire-agent/templates/roles.yaml @@ -2,7 +2,7 @@ kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . | quote }} rules: - apiGroups: [""] resources: @@ -15,12 +15,12 @@ rules: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . | quote }} subjects: - kind: ServiceAccount - name: {{ include "spire-agent.serviceAccountName" . }} - namespace: {{ include "spire-agent.namespace" . }} + name: {{ include "spire-agent.serviceAccountName" . | quote }} + namespace: {{ include "spire-agent.namespace" . | quote }} roleRef: kind: ClusterRole - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . | quote }} apiGroup: rbac.authorization.k8s.io diff --git a/charts/spire/charts/spire-agent/templates/scc-spire-agent.yaml b/charts/spire/charts/spire-agent/templates/scc-spire-agent.yaml index 30d84f1..3c81651 100644 --- a/charts/spire/charts/spire-agent/templates/scc-spire-agent.yaml +++ b/charts/spire/charts/spire-agent/templates/scc-spire-agent.yaml @@ -2,7 +2,7 @@ apiVersion: security.openshift.io/v1 kind: SecurityContextConstraints metadata: - name: {{ include "spire-agent.fullname" . }} + name: {{ include "spire-agent.fullname" . | quote }} readOnlyRootFilesystem: true runAsUser: type: RunAsAny @@ -11,7 +11,7 @@ seLinuxContext: supplementalGroups: type: RunAsAny users: - - system:serviceaccount:{{ include "spire-agent.namespace" . }}:{{ include "spire-agent.serviceAccountName" . }} + - {{ printf "system:serviceaccount:%s:%s" (include "spire-agent.namespace" .) (include "spire-agent.serviceAccountName" .) | quote }} volumes: - configMap - hostPath diff --git a/charts/spire/charts/spire-agent/templates/serviceaccount.yaml b/charts/spire/charts/spire-agent/templates/serviceaccount.yaml index 03e447e..c0c3472 100644 --- a/charts/spire/charts/spire-agent/templates/serviceaccount.yaml +++ b/charts/spire/charts/spire-agent/templates/serviceaccount.yaml @@ -2,8 +2,8 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "spire-agent.serviceAccountName" . }} - namespace: {{ include "spire-agent.namespace" . }} + name: {{ include "spire-agent.serviceAccountName" . | quote }} + namespace: {{ include "spire-agent.namespace" . | quote }} labels: {{- include "spire-agent.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} diff --git a/charts/spire/charts/spire-lib/templates/_helpers.tpl b/charts/spire/charts/spire-lib/templates/_helpers.tpl index db33cee..8e3684a 100644 --- a/charts/spire/charts/spire-lib/templates/_helpers.tpl +++ b/charts/spire/charts/spire-lib/templates/_helpers.tpl @@ -53,17 +53,17 @@ {{- $repo := .image.repository }} {{- $tag := .image.tag | toString }} {{- if eq (substr 0 7 $tag) "sha256:" }} -{{- printf "%s/%s@%s" $registry $repo $tag }} +{{- printf "%s/%s@%s" $registry $repo $tag | quote }} {{- else if .appVersion }} {{- $appVersion := .appVersion }} {{- if and (hasKey . "ubi") (dig "openshift" false .global) }} {{- $appVersion = printf "ubi-%s" $appVersion }} {{- end }} -{{- printf "%s%s:%s" $registry $repo (default $appVersion $tag) }} +{{- printf "%s%s:%s" $registry $repo (default $appVersion $tag) | quote }} {{- else if $tag }} -{{- printf "%s%s:%s" $registry $repo $tag }} +{{- printf "%s%s:%s" $registry $repo $tag | quote }} {{- else }} -{{- printf "%s%s" $registry $repo }} +{{- printf "%s%s" $registry $repo | quote }} {{- end }} {{- end }} @@ -309,7 +309,7 @@ securityContext - the subbranch of values that contains the securityContext to m {{- define "spire-lib.default_node_priority_class_name" }} {{- if .Values.priorityClassName }} -priorityClassName: {{ .Values.priorityClassName }} +priorityClassName: {{ .Values.priorityClassName | quote }} {{- else if and (dig "spire" "recommendations" "enabled" false .Values.global) (dig "spire" "recommendations" "priorityClassName" true .Values.global) }} priorityClassName: system-node-critical {{- end }} @@ -317,7 +317,7 @@ priorityClassName: system-node-critical {{- define "spire-lib.default_cluster_priority_class_name" }} {{- if .Values.priorityClassName }} -priorityClassName: {{ .Values.priorityClassName }} +priorityClassName: {{ .Values.priorityClassName | quote }} {{- else if and (dig "spire" "recommendations" "enabled" false .Values.global) (dig "spire" "recommendations" "priorityClassName" true .Values.global) }} priorityClassName: system-cluster-critical {{- end }}