11package controllers
22
33import (
4+ "context"
5+ "fmt"
6+
7+ corev1 "k8s.io/api/core/v1"
48 k8serrors "k8s.io/apimachinery/pkg/api/errors"
9+ "sigs.k8s.io/controller-runtime/pkg/client"
510)
611
7- // When the feature is enabled, handleFeatureConfidential sets config maps to confidential values.
8- //
9- // Changes the ImageConfigMap, so that the image creation job will create a confidential image.
10- // This will happen at the first reconciliation loop, before the image creation job starts.
11- //
12- // Changes the peer pods configMap to enable confidential.
13- // This will happen likely after several reconciliation loops, because it has prerequisites:
12+ const (
13+ // kata-cc runtime class for CoCo BM
14+ kataCCRuntimeClassName = "kata-cc"
15+ kataCCRuntimeClassCpuOverhead = "0.25"
16+ kataCCRuntimeClassMemOverhead = "350Mi"
17+
18+ // TEE node labels
19+ intelTDXNodeLabel = "intel.feature.node.kubernetes.io/tdx"
20+ amdSNPNodeLabel = "amd.feature.node.kubernetes.io/snp"
21+
22+ // RuntimeClass handlers for TEE
23+ kataCCIntelHandler = "kata-cc-intel"
24+ kataCCAmdHandler = "kata-cc-amd"
25+ )
26+
27+ // When the feature is enabled, handleFeatureConfidential configures confidential computing support.
1428//
15- // - Peer pods must be enabled in the KataConfig .
16- // - The peer pods config map must exist .
29+ // For peer pods: sets ImageConfigMap and peer pods configMap to enable confidential images and CVM support .
30+ // For baremetal: creates kata-cc runtime classes with TEE-specific handlers (Intel TDX or AMD SNP) .
1731//
18- // When the feature is disabled, handleFeatureConfidential resets the config maps to non-confidential values .
32+ // When the feature is disabled, handleFeatureConfidential resets config maps and deletes runtime classes .
1933func (r * KataConfigOpenShiftReconciler ) handleFeatureConfidential (state FeatureGateState ) error {
34+ if r .kataConfig .Spec .EnablePeerPods {
35+ if err := r .handleConfidentialPeerPods (state ); err != nil {
36+ return err
37+ }
38+ }
2039
21- // ImageConfigMap
40+ if err := r .handleConfidentialBaremetal (state ); err != nil {
41+ return err
42+ }
2243
44+ return nil
45+ }
46+
47+ // handleConfidentialPeerPods configures confidential computing for peer pods deployments.
48+ // It manages ImageConfigMap and peer pods configMap to control confidential images and CVM support.
49+ func (r * KataConfigOpenShiftReconciler ) handleConfidentialPeerPods (state FeatureGateState ) error {
50+ // ImageConfigMap
2351 if err := InitializeImageGenerator (r .Client ); err != nil {
2452 return err
2553 }
@@ -56,8 +84,6 @@ func (r *KataConfigOpenShiftReconciler) handleFeatureConfidential(state FeatureG
5684 }
5785 }
5886
59- // peer pods config
60-
6187 // Patch peer pods configMap, if it exists.
6288 var peerpodsCMData map [string ]string
6389 if state == Enabled {
@@ -76,3 +102,81 @@ func (r *KataConfigOpenShiftReconciler) handleFeatureConfidential(state FeatureG
76102
77103 return nil
78104}
105+
106+ // handleConfidentialBaremetal configures confidential computing for baremetal deployments.
107+ // It manages kata-cc runtime classes with TEE-specific handlers (Intel TDX or AMD SNP).
108+ func (r * KataConfigOpenShiftReconciler ) handleConfidentialBaremetal (state FeatureGateState ) error {
109+ if state == Enabled {
110+ r .Log .Info ("Creating " + kataCCRuntimeClassName + " runtime class for confidential containers" )
111+
112+ handler , nodeLabel , err := r .computeTEEHandlerAndLabel ()
113+ if err != nil {
114+ // If peer pods is enabled, just warn and skip baremetal coco
115+ if r .kataConfig .Spec .EnablePeerPods {
116+ r .Log .Info ("WARNING: No TEE hardware detected, skipping baremetal confidential containers (peer pods CVM will handle confidential workloads)" , "err" , err )
117+ return nil
118+ }
119+ // If peer pods disabled, this is an error - user wants baremetal coco but no hardware
120+ r .Log .Info ("failed to detect TEE platform" , "err" , err )
121+ return err
122+ }
123+
124+ // Create kata-cc runtime class restricted to the detected TEE subset
125+ err = r .createRuntimeClass (kataCCRuntimeClassName , kataCCRuntimeClassCpuOverhead , kataCCRuntimeClassMemOverhead , handler , nodeLabel )
126+ if err != nil {
127+ r .Log .Info ("Error creating " + kataCCRuntimeClassName + " runtime class" , "err" , err )
128+ return fmt .Errorf ("Error creating " + kataCCRuntimeClassName + " runtime class: %w" , err )
129+ }
130+
131+ } else {
132+ r .Log .Info ("Deleting " + kataCCRuntimeClassName + " runtime class for confidential containers" )
133+
134+ // Delete kata-cc runtime class
135+ err := r .deleteRuntimeClass (kataCCRuntimeClassName )
136+ if err != nil {
137+ r .Log .Info ("Error deleting " + kataCCRuntimeClassName + " runtime class" , "err" , err )
138+ return fmt .Errorf ("Error deleting " + kataCCRuntimeClassName + " runtime class: %w" , err )
139+ }
140+ }
141+
142+ return nil
143+ }
144+
145+ func (r * KataConfigOpenShiftReconciler ) computeTEEHandlerAndLabel () (string , string , error ) {
146+ selector , err := r .getKataConfigNodeSelectorAsSelector ()
147+ if err != nil {
148+ return "" , "" , fmt .Errorf ("failed to build node selector: %w" , err )
149+ }
150+
151+ nodes := & corev1.NodeList {}
152+ listOpts := []client.ListOption {
153+ client.MatchingLabelsSelector {Selector : selector },
154+ }
155+ if err := r .Client .List (context .TODO (), nodes , listOpts ... ); err != nil {
156+ return "" , "" , fmt .Errorf ("failed to list nodes: %w" , err )
157+ }
158+
159+ var hasIntelTDX bool
160+ var hasAmdSNP bool
161+ for _ , n := range nodes .Items {
162+ if v , ok := n .Labels [intelTDXNodeLabel ]; ok && v == "true" {
163+ hasIntelTDX = true
164+ }
165+ if v , ok := n .Labels [amdSNPNodeLabel ]; ok && v == "true" {
166+ hasAmdSNP = true
167+ }
168+ }
169+
170+ if hasIntelTDX && hasAmdSNP {
171+ return "" , "" , fmt .Errorf ("multiple TEE platforms detected; only one per cluster supported" )
172+ }
173+
174+ if hasIntelTDX {
175+ return kataCCIntelHandler , intelTDXNodeLabel , nil
176+ }
177+ if hasAmdSNP {
178+ return kataCCAmdHandler , amdSNPNodeLabel , nil
179+ }
180+
181+ return "" , "" , fmt .Errorf ("no TEE platform labels found (expected %s or %s)" , intelTDXNodeLabel , amdSNPNodeLabel )
182+ }
0 commit comments