Add direct tpm support for spire-agent (#216)
* Add direct tpm support for spire-agent Signed-off-by: Kevin Fox <[email protected]> * Add fingerprinting support Signed-off-by: Kevin Fox <[email protected]> * Add example Signed-off-by: Kevin Fox <[email protected]> * Update charts/spire/charts/spire-agent/templates/configmap.yaml Signed-off-by: kfox1111 <[email protected]> * Update charts/spire/charts/spire-agent/templates/configmap.yaml Signed-off-by: kfox1111 <[email protected]> * Fix broken tests Signed-off-by: Kevin Fox <[email protected]> * Fix hardcoded nodeAttestor and keyManager in spire-agent Fixes: https://github.com/spiffe/helm-charts-hardened/issues/220 Signed-off-by: Kevin Fox <[email protected]> * Fix merge issues Signed-off-by: Kevin Fox <[email protected]> * Fix unit tests Signed-off-by: Kevin Fox <[email protected]> * Pass the agent's securityContext on to Kubernetes Currently its ignored. Signed-off-by: Kevin Fox <[email protected]> * Update example to be usable Signed-off-by: Kevin Fox <[email protected]> * Apply suggestions from code review Signed-off-by: kfox1111 <[email protected]> * Incorperate feedback Signed-off-by: Kevin Fox <[email protected]> * Incorperate feedback Signed-off-by: Kevin Fox <[email protected]> * Update to the newest release Signed-off-by: Kevin Fox <[email protected]> * Incorperate feedback Signed-off-by: Kevin Fox <[email protected]> * Incorperate feedback Signed-off-by: Kevin Fox <[email protected]> * Apply suggestions from code review Signed-off-by: kfox1111 <[email protected]> --------- Signed-off-by: Kevin Fox <[email protected]> Signed-off-by: kfox1111 <[email protected]> Co-authored-by: Faisal Memon <[email protected]>
This commit is contained in:
@@ -75,6 +75,18 @@ A Helm chart to install the SPIRE agent.
|
|||||||
| `fsGroupFix.resources` | Specify resource needs as per https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | `{}` |
|
| `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` |
|
| `keyManager.memory.enabled` | Enable the memory based Key Manager | `true` |
|
||||||
| `nodeAttestor.k8sPsat.enabled` | Enable Psat k8s Node Attestor | `true` |
|
| `nodeAttestor.k8sPsat.enabled` | Enable Psat k8s Node Attestor | `true` |
|
||||||
|
| `nodeAttestor.tpmDirect.enabled` | Enable the direct TPM node attestor, a 3rd party plugin by Boxboat. This plugin is experimental. | `false` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.image.registry` | The OCI registry to pull the image from | `docker.io` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.image.repository` | The repository within the registry | `boxboat/spire-tpm-plugin-tpm-attestor-agent` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.image.pullPolicy` | The image pull policy | `IfNotPresent` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.image.tag` | Overrides the image tag | `v1.8.7` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.checksum` | The sha256 checksum of the plugin binary | `1d7c73ccac948ee86cbd78ddde2d30128a1838b403f7bb2100d38d916a252244` |
|
||||||
|
| `nodeAttestor.tpmDirect.plugin.path` | The filename in the container of the plugin | `/app/tpm_attestor_agent` |
|
||||||
|
| `nodeAttestor.tpmDirect.pubHash.enabled` | Enable Psat k8s nodeattestor | `true` |
|
||||||
|
| `nodeAttestor.tpmDirect.pubHash.image.registry` | The OCI registry to pull the image from | `docker.io` |
|
||||||
|
| `nodeAttestor.tpmDirect.pubHash.image.repository` | The repository within the registry | `boxboat/spire-tpm-plugin-get-tpm-pubhash` |
|
||||||
|
| `nodeAttestor.tpmDirect.pubHash.image.pullPolicy` | The image pull policy | `IfNotPresent` |
|
||||||
|
| `nodeAttestor.tpmDirect.pubHash.image.tag` | Overrides the image tag | `v1.8.7` |
|
||||||
| `workloadAttestors.unix.enabled` | Enables the Unix workload attestor | `false` |
|
| `workloadAttestors.unix.enabled` | Enables the Unix workload attestor | `false` |
|
||||||
| `workloadAttestors.k8s.enabled` | Enables the Kubernetes workload attestor | `true` |
|
| `workloadAttestors.k8s.enabled` | Enables the Kubernetes workload attestor | `true` |
|
||||||
| `workloadAttestors.k8s.skipKubeletVerification` | If true, kubelet certificate verification is skipped | `true` |
|
| `workloadAttestors.k8s.skipKubeletVerification` | If true, kubelet certificate verification is skipped | `true` |
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ plugins:
|
|||||||
cluster: {{ include "spire-lib.cluster-name" . | quote }}
|
cluster: {{ include "spire-lib.cluster-name" . | quote }}
|
||||||
{{- $nodeAttestorUsed = add1 $nodeAttestorUsed }}
|
{{- $nodeAttestorUsed = add1 $nodeAttestorUsed }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- with .Values.nodeAttestor.tpmDirect }}
|
||||||
|
{{- if eq (.enabled | toString) "true" }}
|
||||||
|
tpm:
|
||||||
|
plugin_cmd: "/tpm/tpm_attestor_agent"
|
||||||
|
plugin_checksum: {{ .plugin.checksum }}
|
||||||
|
plugin_data: {}
|
||||||
|
{{- $nodeAttestorUsed = add1 $nodeAttestorUsed }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{- if ne $nodeAttestorUsed 1 }}
|
{{- if ne $nodeAttestorUsed 1 }}
|
||||||
{{- fail (printf "You have to enable exactly one Node Attestor. There are %d enabled." $nodeAttestorUsed) }}
|
{{- fail (printf "You have to enable exactly one Node Attestor. There are %d enabled." $nodeAttestorUsed) }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
{{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }}
|
{{- $configSum := (include (print $.Template.BasePath "/configmap.yaml") . | sha256sum) }}
|
||||||
{{- $podSecurityContext := fromYaml (include "spire-lib.podsecuritycontext" .) }}
|
{{- $podSecurityContext := fromYaml (include "spire-lib.podsecuritycontext" .) }}
|
||||||
|
{{- $mainSecurityContext := deepCopy .Values.securityContext }}
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.enabled }}
|
||||||
|
{{- $podSecurityContext = mergeOverwrite (dict "runAsUser" 0 "runAsGroup" 0) .Values.podSecurityContext }}
|
||||||
|
{{- $_ := set $mainSecurityContext "privileged" true }}
|
||||||
|
{{- end }}
|
||||||
{{- $cbh := eq (include "spire-agent.connect-by-hostname" .) "true" }}
|
{{- $cbh := eq (include "spire-agent.connect-by-hostname" .) "true" }}
|
||||||
{{- $socketAlternateNames := index (include "spire-agent.socket-alternate-names" . | fromYaml) "names" }}
|
{{- $socketAlternateNames := index (include "spire-agent.socket-alternate-names" . | fromYaml) "names" }}
|
||||||
{{- $socketPath := include "spire-agent.socket-path" . }}
|
{{- $socketPath := include "spire-agent.socket-path" . }}
|
||||||
@@ -41,6 +46,47 @@ spec:
|
|||||||
{{- toYaml .Values.hostAliases | nindent 8 }}
|
{{- toYaml .Values.hostAliases | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
initContainers:
|
initContainers:
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.enabled }}
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.pubHash.enabled }}
|
||||||
|
- name: fingerprint-tpm
|
||||||
|
securityContext:
|
||||||
|
{{- $mainSecurityContext | toYaml | nindent 12 }}
|
||||||
|
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.nodeAttestor.tpmDirect.pubHash.image "global" .Values.global) }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
# Fetch the TPM's fingerprint from the TPM and output it on the Computers Console. This enables secure bootstrapping of the Node with the Server.
|
||||||
|
TPM=`/app/get_tpm_pubhash 2> /dev/null`
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "TPM Fingerprint: $TPM"
|
||||||
|
(echo -n '<1>'; echo "TPM Fingerprint: $TPM") | tee /dev/kmsg
|
||||||
|
else
|
||||||
|
/app/get_tpm_pubhash
|
||||||
|
fi
|
||||||
|
volumeMounts:
|
||||||
|
- name: tpm
|
||||||
|
mountPath: /dev/tpmrm0
|
||||||
|
readOnly: true
|
||||||
|
- name: kmsg
|
||||||
|
mountPath: /dev/kmsg
|
||||||
|
imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.pubHash.image.pullPolicy }}
|
||||||
|
{{- end }}
|
||||||
|
- name: init-tpm-direct
|
||||||
|
securityContext:
|
||||||
|
{{- .Values.securityContext | toYaml | nindent 12 }}
|
||||||
|
image: {{ template "spire-lib.image" (dict "appVersion" $.Chart.AppVersion "image" .Values.nodeAttestor.tpmDirect.plugin.image "global" .Values.global) }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -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
|
||||||
|
volumeMounts:
|
||||||
|
- name: tpm-direct
|
||||||
|
mountPath: /tpm
|
||||||
|
imagePullPolicy: {{ .Values.nodeAttestor.tpmDirect.plugin.image.pullPolicy }}
|
||||||
|
{{- end }}
|
||||||
- name: init
|
- name: init
|
||||||
# This is a small image with wait-for-it, choose whatever image
|
# This is a small image with wait-for-it, choose whatever image
|
||||||
# you prefer that waits for a service to be up. This image is built
|
# you prefer that waits for a service to be up. This image is built
|
||||||
@@ -48,6 +94,8 @@ spec:
|
|||||||
image: {{ template "spire-lib.image" (dict "image" .Values.waitForIt.image "global" .Values.global) }}
|
image: {{ template "spire-lib.image" (dict "image" .Values.waitForIt.image "global" .Values.global) }}
|
||||||
imagePullPolicy: {{ .Values.waitForIt.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.waitForIt.image.pullPolicy }}
|
||||||
args: ["-t", "30", "-h", "{{ include "spire-agent.server-address" . | trim }}", "-p", {{ .Values.server.port | quote }}]
|
args: ["-t", "30", "-h", "{{ include "spire-agent.server-address" . | trim }}", "-p", {{ .Values.server.port | quote }}]
|
||||||
|
securityContext:
|
||||||
|
{{- .Values.securityContext | toYaml | nindent 12 }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.waitForIt.resources | nindent 12 }}
|
{{- toYaml .Values.waitForIt.resources | nindent 12 }}
|
||||||
securityContext:
|
securityContext:
|
||||||
@@ -104,7 +152,7 @@ spec:
|
|||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
args: ["-config", "/opt/spire/conf/agent/agent.conf"]
|
args: ["-config", "/opt/spire/conf/agent/agent.conf"]
|
||||||
securityContext:
|
securityContext:
|
||||||
{{ toYaml .Values.securityContext | nindent 12 }}
|
{{- $mainSecurityContext | toYaml | nindent 12 }}
|
||||||
env:
|
env:
|
||||||
- name: PATH
|
- name: PATH
|
||||||
value: "/opt/spire/bin:/bin"
|
value: "/opt/spire/bin:/bin"
|
||||||
@@ -138,6 +186,14 @@ spec:
|
|||||||
mountPath: /run/spire/bundle
|
mountPath: /run/spire/bundle
|
||||||
readOnly: true
|
readOnly: true
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.enabled }}
|
||||||
|
- name: tpm-direct
|
||||||
|
mountPath: /tpm
|
||||||
|
readOnly: true
|
||||||
|
- name: tpm
|
||||||
|
mountPath: /dev/tpmrm0
|
||||||
|
readOnly: true
|
||||||
|
{{- end }}
|
||||||
- name: spire-agent-socket-dir
|
- name: spire-agent-socket-dir
|
||||||
mountPath: /tmp/spire-agent/public
|
mountPath: /tmp/spire-agent/public
|
||||||
readOnly: false
|
readOnly: false
|
||||||
@@ -191,6 +247,10 @@ spec:
|
|||||||
configMap:
|
configMap:
|
||||||
name: {{ include "spire-lib.bundle-configmap" . }}
|
name: {{ include "spire-lib.bundle-configmap" . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.enabled }}
|
||||||
|
- name: tpm-direct
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
- name: spire-token
|
- name: spire-token
|
||||||
projected:
|
projected:
|
||||||
sources:
|
sources:
|
||||||
@@ -202,6 +262,16 @@ spec:
|
|||||||
hostPath:
|
hostPath:
|
||||||
path: {{ $socketPath | dir }}
|
path: {{ $socketPath | dir }}
|
||||||
type: DirectoryOrCreate
|
type: DirectoryOrCreate
|
||||||
|
{{- if .Values.nodeAttestor.tpmDirect.enabled }}
|
||||||
|
- name: tpm
|
||||||
|
hostPath:
|
||||||
|
path: /dev/tpmrm0
|
||||||
|
type: CharDevice
|
||||||
|
- name: kmsg
|
||||||
|
hostPath:
|
||||||
|
path: /dev/kmsg
|
||||||
|
type: CharDevice
|
||||||
|
{{- end }}
|
||||||
{{- if gt (len .Values.extraVolumes) 0 }}
|
{{- if gt (len .Values.extraVolumes) 0 }}
|
||||||
{{- toYaml .Values.extraVolumes | nindent 8 }}
|
{{- toYaml .Values.extraVolumes | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -171,6 +171,37 @@ nodeAttestor:
|
|||||||
k8sPsat:
|
k8sPsat:
|
||||||
## @param nodeAttestor.k8sPsat.enabled Enable Psat k8s Node Attestor
|
## @param nodeAttestor.k8sPsat.enabled Enable Psat k8s Node Attestor
|
||||||
enabled: true
|
enabled: true
|
||||||
|
tpmDirect:
|
||||||
|
## @param nodeAttestor.tpmDirect.enabled Enable the direct TPM node attestor, a 3rd party plugin by Boxboat. This plugin is experimental.
|
||||||
|
enabled: false
|
||||||
|
plugin:
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.image.registry The OCI registry to pull the image from
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.image.repository The repository within the registry
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.image.pullPolicy The image pull policy
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.image.tag Overrides the image tag
|
||||||
|
##
|
||||||
|
image:
|
||||||
|
registry: docker.io
|
||||||
|
repository: boxboat/spire-tpm-plugin-tpm-attestor-agent
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: "v1.8.7"
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.checksum The sha256 checksum of the plugin binary
|
||||||
|
checksum: 1d7c73ccac948ee86cbd78ddde2d30128a1838b403f7bb2100d38d916a252244
|
||||||
|
## @param nodeAttestor.tpmDirect.plugin.path The filename in the container of the plugin
|
||||||
|
path: /app/tpm_attestor_agent
|
||||||
|
pubHash:
|
||||||
|
## @param nodeAttestor.tpmDirect.pubHash.enabled Enable Psat k8s nodeattestor
|
||||||
|
enabled: true
|
||||||
|
## @param nodeAttestor.tpmDirect.pubHash.image.registry The OCI registry to pull the image from
|
||||||
|
## @param nodeAttestor.tpmDirect.pubHash.image.repository The repository within the registry
|
||||||
|
## @param nodeAttestor.tpmDirect.pubHash.image.pullPolicy The image pull policy
|
||||||
|
## @param nodeAttestor.tpmDirect.pubHash.image.tag Overrides the image tag
|
||||||
|
##
|
||||||
|
image:
|
||||||
|
registry: docker.io
|
||||||
|
repository: boxboat/spire-tpm-plugin-get-tpm-pubhash
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: "v1.8.7"
|
||||||
|
|
||||||
# workloadAttestors determine a workload's properties and then generate a set of selectors associated with it.
|
# workloadAttestors determine a workload's properties and then generate a set of selectors associated with it.
|
||||||
workloadAttestors:
|
workloadAttestors:
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user