mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-31 04:04:51 +00:00
deploy: add spire manifests in helm and kustomize
Signed-off-by: TessaIO <ahmedgrati1999@gmail.com> Signed-off-by: AhmedGrati <ahmedgrati1999@gmail.com>
This commit is contained in:
parent
c77c370d0d
commit
73e31a879b
14 changed files with 275 additions and 119 deletions
6
deployment/helm/node-feature-discovery/Chart.lock
Normal file
6
deployment/helm/node-feature-discovery/Chart.lock
Normal file
|
@ -0,0 +1,6 @@
|
|||
dependencies:
|
||||
- name: spire
|
||||
repository: https://spiffe.github.io/helm-charts-hardened/
|
||||
version: 0.24.1
|
||||
digest: sha256:f3b4dc973a59682bf3aa5ca9b53322f57935dd093081e82a37b8082e00becbe9
|
||||
generated: "2024-12-20T16:52:40.180416+01:00"
|
|
@ -13,3 +13,8 @@ keywords:
|
|||
- node-labels
|
||||
type: application
|
||||
version: 0.2.1
|
||||
dependencies:
|
||||
- name: spire
|
||||
version: 0.24.1
|
||||
repository: https://spiffe.github.io/helm-charts-hardened/
|
||||
condition: spire.enabled
|
||||
|
|
BIN
deployment/helm/node-feature-discovery/charts/spire-0.24.1.tgz
Normal file
BIN
deployment/helm/node-feature-discovery/charts/spire-0.24.1.tgz
Normal file
Binary file not shown.
|
@ -145,11 +145,25 @@ spec:
|
|||
{{- with .Values.master.extraArgs }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.spire.enabled }}
|
||||
- "-enable-spiffe"
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.spire.enabled }}
|
||||
- name: spire-agent-socket
|
||||
mountPath: /run/spire/agent-sockets/api.sock
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
- name: nfd-master-conf
|
||||
mountPath: "/etc/kubernetes/node-feature-discovery"
|
||||
readOnly: true
|
||||
volumes:
|
||||
{{- if .Values.spire.enabled }}
|
||||
- name: spire-agent-socket
|
||||
hostPath:
|
||||
path: /run/spire/agent-sockets/api.sock
|
||||
type: Socket
|
||||
{{- end }}
|
||||
- name: nfd-master-conf
|
||||
configMap:
|
||||
name: {{ include "node-feature-discovery.fullname" . }}-master-conf
|
||||
|
|
|
@ -110,10 +110,18 @@ spec:
|
|||
{{- with .Values.worker.extraArgs }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.spire.enabled }}
|
||||
- "-enable-spiffe"
|
||||
{{- end }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.worker.port | default "8080"}}
|
||||
name: http
|
||||
volumeMounts:
|
||||
{{- if .Values.spire.enabled }}
|
||||
- name: spire-agent-socket
|
||||
mountPath: /run/spire/agent-sockets/api.sock
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
- name: host-boot
|
||||
mountPath: "/host-boot"
|
||||
readOnly: true
|
||||
|
@ -144,6 +152,12 @@ spec:
|
|||
mountPath: "/etc/kubernetes/node-feature-discovery"
|
||||
readOnly: true
|
||||
volumes:
|
||||
{{- if .Values.spire.enabled }}
|
||||
- name: spire-agent-socket
|
||||
hostPath:
|
||||
path: /run/spire/agent-sockets/api.sock
|
||||
type: Socket
|
||||
{{- end }}
|
||||
- name: host-boot
|
||||
hostPath:
|
||||
path: "/boot"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
image:
|
||||
repository: gcr.io/k8s-staging-nfd/node-feature-discovery
|
||||
repository: docker.io/ahmedgrati/node-feature-discovery
|
||||
# This should be set to 'IfNotPresent' for released version
|
||||
pullPolicy: Always
|
||||
# tag, if defined will use the given image tag, else Chart.AppVersion will be used
|
||||
# tag
|
||||
tag: v0.18.0-devel-105-gb1d33c2b2-dirty
|
||||
imagePullSecrets: []
|
||||
|
||||
nameOverride: ""
|
||||
|
@ -574,3 +574,57 @@ prometheus:
|
|||
enable: false
|
||||
scrapeInterval: 10s
|
||||
labels: {}
|
||||
|
||||
spire:
|
||||
enabled: true
|
||||
global:
|
||||
spire:
|
||||
clusterName: "nfd"
|
||||
trustDomain: "nfd.k8s-sigs.io"
|
||||
system:
|
||||
name: "spire-system"
|
||||
create: false
|
||||
server:
|
||||
name: "spire-server"
|
||||
create: false
|
||||
spire-agent:
|
||||
nameOverride: "spire-agent"
|
||||
kubeletConnectByHostname: "true"
|
||||
server:
|
||||
address: "nfd-spire-server.nfd"
|
||||
workloadAttestors:
|
||||
unix:
|
||||
enabled: true
|
||||
spire-server:
|
||||
nameOverride: "spire-server"
|
||||
controllerManager:
|
||||
enabled: true
|
||||
identities:
|
||||
clusterStaticEntries:
|
||||
node:
|
||||
parentID: spiffe://nfd.k8s-sigs.io/spire/server
|
||||
spiffeID: spiffe://nfd.k8s-sigs.io/root
|
||||
selectors:
|
||||
- k8s_psat:agent_ns:nfd
|
||||
- k8s_psat:agent_sa:nfd-agent
|
||||
- k8s_psat:cluster:nfd
|
||||
nfd:
|
||||
parentID: spiffe://nfd.k8s-sigs.io/root
|
||||
spiffeID: spiffe://nfd.k8s-sigs.io/worker
|
||||
selectors:
|
||||
- k8s:pod-label:app.kubernetes.io/name:node-feature-discovery
|
||||
|
||||
|
||||
caSubject:
|
||||
commonName: "nfd.k8s-sigs.io"
|
||||
country: "US"
|
||||
organization: "SPIFFE"
|
||||
|
||||
upstream:
|
||||
enabled: false
|
||||
spiffe-csi-driver:
|
||||
enabled: false
|
||||
spiffe-oidc-discovery-provider:
|
||||
enabled: false
|
||||
tornjak-frontend:
|
||||
enabled: false
|
||||
|
|
|
@ -306,3 +306,19 @@ Example:
|
|||
```bash
|
||||
nfd-master -resync-period=2h
|
||||
```
|
||||
|
||||
### -enable-spiffe
|
||||
|
||||
the `-enable-spiffe` flag enables SPIFFE verification for the created NodeFeature
|
||||
objects created by the worker. When enabled, master verifies the signature that
|
||||
is put on the annotations part of the NodeFeature object, and updates
|
||||
Kubernetes nodes if the signature is verified. The feature should be enabled,
|
||||
after deploying SPIFFE, and you can do it through the Helm chart.
|
||||
|
||||
Default: false.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
nfd-master -enable-spiffe
|
||||
```
|
||||
|
|
|
@ -273,3 +273,19 @@ Default: 0
|
|||
Comma-separated list of `pattern=N` settings for file-filtered logging.
|
||||
|
||||
Default: *empty*
|
||||
|
||||
### -enable-spiffe
|
||||
|
||||
the `-enable-spiffe` flag enables signing NodeFeature spec on the worker side
|
||||
and puts the signature in the annotations side of the NodeFeature object.
|
||||
The signature is verified afterwards by the master. The feature
|
||||
should be enabled, after deploying SPIFFE, and you can do it through
|
||||
the Helm chart.
|
||||
|
||||
Default: false.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
nfd-master -enable-spiffe
|
||||
```
|
||||
|
|
3
go.mod
3
go.mod
|
@ -19,6 +19,7 @@ require (
|
|||
github.com/prometheus/client_golang v1.21.0
|
||||
github.com/smartystreets/goconvey v1.8.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||
|
@ -71,6 +72,7 @@ require (
|
|||
github.com/euank/go-kmsg-parser v2.0.0+incompatible // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
|
@ -131,6 +133,7 @@ require (
|
|||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
|
||||
|
|
28
go.sum
28
go.sum
|
@ -76,6 +76,8 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
|
|||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
|
@ -123,27 +125,6 @@ github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/Z
|
|||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw=
|
||||
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
|
@ -276,6 +257,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
|||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
@ -283,7 +266,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
|||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
@ -301,6 +283,8 @@ github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chq
|
|||
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
|
||||
|
|
|
@ -51,12 +51,6 @@ import (
|
|||
"sigs.k8s.io/yaml"
|
||||
|
||||
nfdclientset "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned"
|
||||
klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
|
||||
spiffe "sigs.k8s.io/node-feature-discovery/pkg/utils/spiffe"
|
||||
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/nodefeaturerule"
|
||||
|
@ -64,11 +58,12 @@ import (
|
|||
nfdfeatures "sigs.k8s.io/node-feature-discovery/pkg/features"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/utils"
|
||||
klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
|
||||
spiffe "sigs.k8s.io/node-feature-discovery/pkg/utils/spiffe"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/version"
|
||||
)
|
||||
|
||||
// SocketPath specifies Spiffe Socket Path
|
||||
const SocketPath = "unix:///run/spire/sockets/agent.sock"
|
||||
const SocketPath = "unix:///run/spire/agent-sockets/api.sock"
|
||||
|
||||
// Labels are a Kubernetes representation of discovered features.
|
||||
type Labels map[string]string
|
||||
|
@ -219,12 +214,6 @@ func NewNfdMaster(opts ...NfdMasterOption) (NfdMaster, error) {
|
|||
|
||||
nfd.updaterPool = newUpdaterPool(nfd)
|
||||
|
||||
spiffeClient, err := spiffe.NewSpiffeClient(SocketPath)
|
||||
if err != nil {
|
||||
return nfd, err
|
||||
}
|
||||
nfd.spiffeClient = spiffeClient
|
||||
|
||||
return nfd, nil
|
||||
}
|
||||
|
||||
|
@ -308,6 +297,14 @@ func (m *nfdMaster) Run() error {
|
|||
}
|
||||
}
|
||||
|
||||
if m.config.EnableSpiffe {
|
||||
spiffeClient, err := spiffe.NewSpiffeClient(SocketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.spiffeClient = spiffeClient
|
||||
}
|
||||
|
||||
httpMux := http.NewServeMux()
|
||||
|
||||
// Register to metrics server
|
||||
|
@ -642,6 +639,14 @@ func (m *nfdMaster) getAndMergeNodeFeatures(nodeName string) (*nfdv1alpha1.NodeF
|
|||
return filteredObjs[i].Namespace < filteredObjs[j].Namespace
|
||||
})
|
||||
|
||||
// If spiffe is enabled, we should filter out the non verified NFD objects
|
||||
if m.config.EnableSpiffe {
|
||||
filteredObjs, err = m.getVerifiedNFDObjects(filteredObjs)
|
||||
if err != nil {
|
||||
return &nfdv1alpha1.NodeFeature{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(filteredObjs) > 0 {
|
||||
// Merge in features
|
||||
//
|
||||
|
@ -697,55 +702,6 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(cli k8sclient.Interface, node *corev1.No
|
|||
return fmt.Errorf("failed to merge NodeFeature objects for node %q: %w", node.Name, err)
|
||||
}
|
||||
|
||||
// Sort our objects
|
||||
sort.Slice(objs, func(i, j int) bool {
|
||||
// Objects in our nfd namespace gets into the beginning of the list
|
||||
if objs[i].Namespace == m.namespace && objs[j].Namespace != m.namespace {
|
||||
return true
|
||||
}
|
||||
if objs[i].Namespace != m.namespace && objs[j].Namespace == m.namespace {
|
||||
return false
|
||||
}
|
||||
// After the nfd namespace, sort objects by their name
|
||||
if objs[i].Name != objs[j].Name {
|
||||
return objs[i].Name < objs[j].Name
|
||||
}
|
||||
// Objects with the same name are sorted by their namespace
|
||||
return objs[i].Namespace < objs[j].Namespace
|
||||
})
|
||||
|
||||
// If spiffe is enabled, we should filter out the non verified NFD objects
|
||||
if m.config.EnableSpiffe {
|
||||
objs, err = m.getVerifiedNFDObjects(objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
klog.V(1).InfoS("processing of node initiated by NodeFeature API", "nodeName", node.Name)
|
||||
|
||||
features := nfdv1alpha1.NewNodeFeatureSpec()
|
||||
|
||||
if len(objs) > 0 {
|
||||
// Merge in features
|
||||
//
|
||||
// NOTE: changing the rule api to support handle multiple objects instead
|
||||
// of merging would probably perform better with lot less data to copy.
|
||||
features = objs[0].Spec.DeepCopy()
|
||||
if m.config.AutoDefaultNs {
|
||||
features.Labels = addNsToMapKeys(features.Labels, nfdv1alpha1.FeatureLabelNs)
|
||||
}
|
||||
for _, o := range objs[1:] {
|
||||
s := o.Spec.DeepCopy()
|
||||
if m.config.AutoDefaultNs {
|
||||
s.Labels = addNsToMapKeys(s.Labels, nfdv1alpha1.FeatureLabelNs)
|
||||
}
|
||||
s.MergeInto(features)
|
||||
}
|
||||
|
||||
klog.V(4).InfoS("merged nodeFeatureSpecs", "newNodeFeatureSpec", utils.DelayedDumper(features))
|
||||
}
|
||||
|
||||
// Update node labels et al. This may also mean removing all NFD-owned
|
||||
// labels (et al.), for example in the case no NodeFeature objects are
|
||||
// present.
|
||||
|
@ -1469,16 +1425,22 @@ func (m *nfdMaster) getVerifiedNFDObjects(objs []*v1alpha1.NodeFeature) ([]*v1al
|
|||
}
|
||||
|
||||
for _, obj := range objs {
|
||||
isSignatureVerified, err := spiffe.VerifyDataSignature(obj.Spec, obj.Annotations["signature"], workerPrivateKey, workerPublicKey)
|
||||
spiffeObj := spiffe.SpiffeObject{
|
||||
Spec: obj.Spec,
|
||||
Name: obj.Name,
|
||||
Namespace: obj.Namespace,
|
||||
Labels: obj.Labels,
|
||||
}
|
||||
isSignatureVerified, err := spiffe.VerifyDataSignature(spiffeObj, obj.Annotations["signature"], workerPrivateKey, workerPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify NodeFeature signature: %w", err)
|
||||
}
|
||||
|
||||
if isSignatureVerified {
|
||||
klog.InfoS("NodeFeature verified", "NodeFeature name", obj.Name)
|
||||
klog.InfoS("NodeFeature verified", "nodefeature", klog.KObj(obj))
|
||||
verifiedObjects = append(verifiedObjects, obj)
|
||||
} else {
|
||||
klog.InfoS("NodeFeature not verified, skipping...", "NodeFeature name", obj.Name)
|
||||
klog.InfoS("NodeFeature not verified, skipping...", "nodefeature", klog.KObj(obj))
|
||||
}
|
||||
}
|
||||
return verifiedObjects, nil
|
||||
|
|
|
@ -17,8 +17,6 @@ limitations under the License.
|
|||
package nfdworker
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -67,7 +65,7 @@ import (
|
|||
)
|
||||
|
||||
// SocketPath specifies Spiffe Socket Path
|
||||
const SocketPath = "unix:///run/spire/sockets/agent.sock"
|
||||
const SocketPath = "unix:///run/spire/agent-sockets/api.sock"
|
||||
|
||||
// NfdWorker is the interface for nfd-worker daemon
|
||||
type NfdWorker interface {
|
||||
|
@ -198,12 +196,6 @@ func NewNfdWorker(opts ...NfdWorkerOption) (NfdWorker, error) {
|
|||
nfd.k8sClient = cli
|
||||
}
|
||||
|
||||
spiffeClient, err := spiffe.NewSpiffeClient(SocketPath)
|
||||
if err != nil {
|
||||
return nfd, err
|
||||
}
|
||||
nfd.spiffeClient = spiffeClient
|
||||
|
||||
return nfd, nil
|
||||
}
|
||||
|
||||
|
@ -326,6 +318,14 @@ func (w *nfdWorker) Run() error {
|
|||
httpMux.Handle("/metrics", promhttp.HandlerFor(promRegistry, promhttp.HandlerOpts{}))
|
||||
registerVersion(version.Get())
|
||||
|
||||
if w.config.Core.EnableSpiffe {
|
||||
spiffeClient, err := spiffe.NewSpiffeClient(SocketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.spiffeClient = spiffeClient
|
||||
}
|
||||
|
||||
err = w.runFeatureDiscovery()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -654,6 +654,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
|
|||
Annotations: map[string]string{nfdv1alpha1.WorkerVersionAnnotation: version.Get()},
|
||||
Labels: map[string]string{nfdv1alpha1.NodeFeatureObjNodeNameLabel: nodename},
|
||||
OwnerReferences: m.ownerReference,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: nfdv1alpha1.NodeFeatureSpec{
|
||||
Features: *features,
|
||||
|
@ -664,8 +665,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
|
|||
|
||||
// If Spiffe is enabled, we add the signature to the annotations section
|
||||
if m.config.Core.EnableSpiffe {
|
||||
err = m.signNodeFeatureCR(nfr)
|
||||
if err != nil {
|
||||
if err = m.signNodeFeatureCR(nfr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -761,7 +761,13 @@ func (m *nfdWorker) signNodeFeatureCR(nfr *nfdv1alpha1.NodeFeature) error {
|
|||
return fmt.Errorf("error while getting worker keys: %w", err)
|
||||
}
|
||||
|
||||
signature, err := spiffe.SignData(nfr.Spec, workerPrivateKey)
|
||||
spiffeObject := spiffe.SpiffeObject{
|
||||
Spec: nfr.Spec,
|
||||
Name: nfr.Name,
|
||||
Namespace: nfr.Namespace,
|
||||
Labels: nfr.Labels,
|
||||
}
|
||||
signature, err := spiffe.SignData(spiffeObject, workerPrivateKey)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign CRD data using Spiffe: %w", err)
|
||||
|
|
|
@ -3,7 +3,9 @@ Copyright 2024 The Kubernetes Authors.
|
|||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -11,7 +13,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
package spiffe
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -25,15 +27,26 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/spiffe/go-spiffe/v2/workloadapi"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
||||
)
|
||||
|
||||
type SpiffeObject struct {
|
||||
Spec nfdv1alpha1.NodeFeatureSpec
|
||||
Name string
|
||||
Namespace string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// WorkerSpiffeID is the SpiffeID of the worker
|
||||
const WorkerSpiffeID = "spiffe://nfd.com/worker"
|
||||
const WorkerSpiffeID = "spiffe://nfd.k8s-sigs.io/worker"
|
||||
|
||||
type SpiffeClient struct {
|
||||
WorkloadApiClient workloadapi.Client
|
||||
}
|
||||
|
||||
var hash_signature_cache = map[string][]byte{}
|
||||
|
||||
func NewSpiffeClient(socketPath string) (*SpiffeClient, error) {
|
||||
spiffeClient := SpiffeClient{}
|
||||
workloadApiClient, err := workloadapi.New(context.Background(), workloadapi.WithAddr(socketPath))
|
||||
|
@ -44,33 +57,38 @@ func NewSpiffeClient(socketPath string) (*SpiffeClient, error) {
|
|||
return &spiffeClient, nil
|
||||
}
|
||||
|
||||
func SignData(data interface{}, privateKey crypto.Signer) ([]byte, error) {
|
||||
func SignData(data SpiffeObject, privateKey crypto.Signer) ([]byte, error) {
|
||||
stringifyData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
dataHash := sha256.Sum256([]byte(stringifyData))
|
||||
if signature, ok := hash_signature_cache[string(dataHash[:])]; ok {
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
var signedData []byte
|
||||
switch t := privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
signedData, err := rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), crypto.SHA256, dataHash[:])
|
||||
signedData, err = rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), crypto.SHA256, dataHash[:])
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return signedData, nil
|
||||
case *ecdsa.PrivateKey:
|
||||
signedData, err := ecdsa.SignASN1(rand.Reader, privateKey.(*ecdsa.PrivateKey), dataHash[:])
|
||||
signedData, err = ecdsa.SignASN1(rand.Reader, privateKey.(*ecdsa.PrivateKey), dataHash[:])
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return signedData, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown private key type: %v", t)
|
||||
}
|
||||
|
||||
hash_signature_cache[string(dataHash[:])] = signedData
|
||||
return signedData, nil
|
||||
}
|
||||
|
||||
func VerifyDataSignature(data interface{}, signedData string, privateKey crypto.Signer, publicKey crypto.PublicKey) (bool, error) {
|
||||
func VerifyDataSignature(data SpiffeObject, signedData string, privateKey crypto.Signer, publicKey crypto.PublicKey) (bool, error) {
|
||||
stringifyData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -83,10 +101,6 @@ func VerifyDataSignature(data interface{}, signedData string, privateKey crypto.
|
|||
|
||||
dataHash := sha256.Sum256([]byte(stringifyData))
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch t := privateKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
err = rsa.VerifyPKCS1v15(publicKey.(*rsa.PublicKey), crypto.SHA256, dataHash[:], decodedSignature)
|
||||
|
@ -112,7 +126,7 @@ func (s *SpiffeClient) GetWorkerKeys() (crypto.Signer, crypto.PublicKey, error)
|
|||
|
||||
for _, svid := range svids {
|
||||
if svid.ID.String() == WorkerSpiffeID {
|
||||
return svid.PrivateKey, svid.PrivateKey.Public, nil
|
||||
return svid.PrivateKey, svid.PrivateKey.Public(), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@ Copyright 2024 The Kubernetes Authors.
|
|||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -11,7 +13,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
package spiffe
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
|
@ -76,20 +78,31 @@ func TestVerify(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
signedData, err := SignData(spec, tt.privateKey)
|
||||
spiffeObj := SpiffeObject{
|
||||
Spec: spec,
|
||||
Name: "test",
|
||||
Namespace: "test",
|
||||
Labels: map[string]string{
|
||||
"random": "test",
|
||||
},
|
||||
}
|
||||
signedData, err := SignData(spiffeObj, tt.privateKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
isVerified, err := VerifyDataSignature(spec, b64.StdEncoding.EncodeToString(signedData), tt.privateKey, tt.publicKey)
|
||||
isVerified, err := VerifyDataSignature(spiffeObj, b64.StdEncoding.EncodeToString(signedData), tt.privateKey, tt.publicKey)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, isVerified)
|
||||
|
||||
signedData = append(signedData, "random"...)
|
||||
isVerified, err = VerifyDataSignature(spec, b64.StdEncoding.EncodeToString(signedData), tt.privateKey, tt.publicKey)
|
||||
isVerified, err = VerifyDataSignature(spiffeObj, b64.StdEncoding.EncodeToString(signedData), tt.privateKey, tt.publicKey)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.False(t, isVerified)
|
||||
}
|
||||
|
||||
// invalidateCache
|
||||
hash_signature_cache = map[string][]byte{}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +126,56 @@ func TestSignData(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
_, err := SignData(spec, tt.privateKey)
|
||||
spiffeObj := SpiffeObject{
|
||||
Spec: spec,
|
||||
Name: "test",
|
||||
Namespace: "test",
|
||||
Labels: map[string]string{
|
||||
"random": "test",
|
||||
},
|
||||
}
|
||||
_, err := SignData(spiffeObj, tt.privateKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// invalidate cache
|
||||
hash_signature_cache = map[string][]byte{}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignCached(t *testing.T) {
|
||||
rsaPrivateKey, _ := mockWorkerRSAPrivateKey()
|
||||
ecdsaPrivateKey, _ := mockWorkerECDSAPrivateKey()
|
||||
spec := mockNFRSpec()
|
||||
|
||||
tc := []struct {
|
||||
name string
|
||||
privateKey crypto.Signer
|
||||
}{
|
||||
{
|
||||
name: "RSA Keys",
|
||||
privateKey: rsaPrivateKey,
|
||||
},
|
||||
{
|
||||
name: "ECDSA Keys",
|
||||
privateKey: ecdsaPrivateKey,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
spiffeObj := SpiffeObject{
|
||||
Spec: spec,
|
||||
Name: "test",
|
||||
Namespace: "test",
|
||||
Labels: map[string]string{
|
||||
"random": "test",
|
||||
},
|
||||
}
|
||||
firstSignature, err := SignData(spiffeObj, tt.privateKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
secondSignature, err := SignData(spiffeObj, tt.privateKey)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, string(firstSignature[:]), string(secondSignature[:]))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue