@@ -51,6 +51,13 @@ import (
51
51
"sigs.k8s.io/yaml"
52
52
53
53
nfdclientset "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned"
54
+ klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
55
+ spiffe "sigs.k8s.io/node-feature-discovery/pkg/utils/spiffe"
56
+
57
+ taintutils "k8s.io/kubernetes/pkg/util/taints"
58
+ "sigs.k8s.io/yaml"
59
+
60
+ "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
54
61
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
55
62
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/nodefeaturerule"
56
63
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/validate"
@@ -60,6 +67,9 @@ import (
60
67
"sigs.k8s.io/node-feature-discovery/pkg/version"
61
68
)
62
69
70
+ // SocketPath specifies Spiffe Socket Path
71
+ const SocketPath = "unix:///run/spire/sockets/agent.sock"
72
+
63
73
// Labels are a Kubernetes representation of discovered features.
64
74
type Labels map [string ]string
65
75
@@ -92,6 +102,7 @@ type NFDConfig struct {
92
102
NfdApiParallelism int
93
103
Klog klogutils.KlogConfigOpts
94
104
Restrictions Restrictions
105
+ EnableSpiffe bool
95
106
}
96
107
97
108
// LeaderElectionConfig contains the configuration for leader election
@@ -110,6 +121,7 @@ type ConfigOverrideArgs struct {
110
121
NoPublish * bool
111
122
ResyncPeriod * utils.DurationVal
112
123
NfdApiParallelism * int
124
+ EnableSpiffe * bool
113
125
}
114
126
115
127
// Args holds command line arguments
@@ -149,7 +161,8 @@ type nfdMaster struct {
149
161
nfdClient nfdclientset.Interface
150
162
updaterPool * updaterPool
151
163
deniedNs
152
- config * NFDConfig
164
+ config * NFDConfig
165
+ spiffeClient * spiffe.SpiffeClient
153
166
}
154
167
155
168
// NewNfdMaster creates a new NfdMaster server instance.
@@ -206,6 +219,12 @@ func NewNfdMaster(opts ...NfdMasterOption) (NfdMaster, error) {
206
219
207
220
nfd .updaterPool = newUpdaterPool (nfd )
208
221
222
+ spiffeClient , err := spiffe .NewSpiffeClient (SocketPath )
223
+ if err != nil {
224
+ return nfd , err
225
+ }
226
+ nfd .spiffeClient = spiffeClient
227
+
209
228
return nfd , nil
210
229
}
211
230
@@ -247,14 +266,15 @@ func newDefaultConfig() *NFDConfig {
247
266
RetryPeriod : utils.DurationVal {Duration : time .Duration (2 ) * time .Second },
248
267
RenewDeadline : utils.DurationVal {Duration : time .Duration (10 ) * time .Second },
249
268
},
250
- Klog : make (map [string ]string ),
251
269
Restrictions : Restrictions {
252
270
DisableLabels : false ,
253
271
DisableExtendedResources : false ,
254
272
DisableAnnotations : false ,
255
273
AllowOverwrite : true ,
256
274
DenyNodeFeatureLabels : false ,
257
275
},
276
+ Klog : make (map [string ]string ),
277
+ EnableSpiffe : false ,
258
278
}
259
279
}
260
280
@@ -677,6 +697,55 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(cli k8sclient.Interface, node *corev1.No
677
697
return fmt .Errorf ("failed to merge NodeFeature objects for node %q: %w" , node .Name , err )
678
698
}
679
699
700
+ // Sort our objects
701
+ sort .Slice (objs , func (i , j int ) bool {
702
+ // Objects in our nfd namespace gets into the beginning of the list
703
+ if objs [i ].Namespace == m .namespace && objs [j ].Namespace != m .namespace {
704
+ return true
705
+ }
706
+ if objs [i ].Namespace != m .namespace && objs [j ].Namespace == m .namespace {
707
+ return false
708
+ }
709
+ // After the nfd namespace, sort objects by their name
710
+ if objs [i ].Name != objs [j ].Name {
711
+ return objs [i ].Name < objs [j ].Name
712
+ }
713
+ // Objects with the same name are sorted by their namespace
714
+ return objs [i ].Namespace < objs [j ].Namespace
715
+ })
716
+
717
+ // If spiffe is enabled, we should filter out the non verified NFD objects
718
+ if m .config .EnableSpiffe {
719
+ objs , err = m .getVerifiedNFDObjects (objs )
720
+ if err != nil {
721
+ return err
722
+ }
723
+ }
724
+
725
+ klog .V (1 ).InfoS ("processing of node initiated by NodeFeature API" , "nodeName" , node .Name )
726
+
727
+ features := nfdv1alpha1 .NewNodeFeatureSpec ()
728
+
729
+ if len (objs ) > 0 {
730
+ // Merge in features
731
+ //
732
+ // NOTE: changing the rule api to support handle multiple objects instead
733
+ // of merging would probably perform better with lot less data to copy.
734
+ features = objs [0 ].Spec .DeepCopy ()
735
+ if m .config .AutoDefaultNs {
736
+ features .Labels = addNsToMapKeys (features .Labels , nfdv1alpha1 .FeatureLabelNs )
737
+ }
738
+ for _ , o := range objs [1 :] {
739
+ s := o .Spec .DeepCopy ()
740
+ if m .config .AutoDefaultNs {
741
+ s .Labels = addNsToMapKeys (s .Labels , nfdv1alpha1 .FeatureLabelNs )
742
+ }
743
+ s .MergeInto (features )
744
+ }
745
+
746
+ klog .V (4 ).InfoS ("merged nodeFeatureSpecs" , "newNodeFeatureSpec" , utils .DelayedDumper (features ))
747
+ }
748
+
680
749
// Update node labels et al. This may also mean removing all NFD-owned
681
750
// labels (et al.), for example in the case no NodeFeature objects are
682
751
// present.
@@ -1187,6 +1256,9 @@ func (m *nfdMaster) configure(filepath string, overrides string) error {
1187
1256
if m .args .Overrides .NfdApiParallelism != nil {
1188
1257
c .NfdApiParallelism = * m .args .Overrides .NfdApiParallelism
1189
1258
}
1259
+ if m .args .Overrides .EnableSpiffe != nil {
1260
+ c .EnableSpiffe = * m .args .Overrides .EnableSpiffe
1261
+ }
1190
1262
1191
1263
if c .NfdApiParallelism <= 0 {
1192
1264
return fmt .Errorf ("the maximum number of concurrent labelers should be a non-zero positive number" )
@@ -1387,3 +1459,27 @@ func patchNode(cli k8sclient.Interface, nodeName string, patches []utils.JsonPat
1387
1459
func patchNodeStatus (cli k8sclient.Interface , nodeName string , patches []utils.JsonPatch ) error {
1388
1460
return patchNode (cli , nodeName , patches , "status" )
1389
1461
}
1462
+
1463
+ func (m * nfdMaster ) getVerifiedNFDObjects (objs []* v1alpha1.NodeFeature ) ([]* v1alpha1.NodeFeature , error ) {
1464
+ verifiedObjects := []* v1alpha1.NodeFeature {}
1465
+
1466
+ workerPrivateKey , workerPublicKey , err := m .spiffeClient .GetWorkerKeys ()
1467
+ if err != nil {
1468
+ return verifiedObjects , err
1469
+ }
1470
+
1471
+ for _ , obj := range objs {
1472
+ isSignatureVerified , err := spiffe .VerifyDataSignature (obj .Spec , obj .Annotations ["signature" ], workerPrivateKey , workerPublicKey )
1473
+ if err != nil {
1474
+ return nil , fmt .Errorf ("failed to verify NodeFeature signature: %w" , err )
1475
+ }
1476
+
1477
+ if isSignatureVerified {
1478
+ klog .InfoS ("NodeFeature verified" , "NodeFeature name" , obj .Name )
1479
+ verifiedObjects = append (verifiedObjects , obj )
1480
+ } else {
1481
+ klog .InfoS ("NodeFeature not verified, skipping..." , "NodeFeature name" , obj .Name )
1482
+ }
1483
+ }
1484
+ return verifiedObjects , nil
1485
+ }
0 commit comments