Skip to content

Commit f6ee4f3

Browse files
authored
Merge pull request #2103 from mythi/PR-2025-013
sgx: add two special resources for quoting daemon and SGX platform registration
2 parents 47ba5ee + cf9f776 commit f6ee4f3

File tree

10 files changed

+115
-13
lines changed

10 files changed

+115
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ The [SGX device plugin](cmd/sgx_plugin/README.md) allows workloads to use
117117
Intel® Software Guard Extensions (Intel® SGX) on
118118
platforms with SGX Flexible Launch Control enabled, e.g.,:
119119

120-
- 3rd Generation Intel® Xeon® Scalable processor family, code-named “Ice Lake”
120+
- 3rd Generation Intel® Xeon® Scalable processor family, and later
121121
- Intel® Xeon® E3 processor
122122
- Intel® NUC Kit NUC7CJYH
123123

cmd/sgx_plugin/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Table of Contents
1919
The Intel SGX device plugin and related components allow workloads to use Intel SGX on
2020
platforms with SGX Flexible Launch Control enabled, e.g.,:
2121

22-
- 3rd/4th Generation Intel® Xeon® Scalable Platforms
22+
- 3rd Generation Intel® Xeon® Scalable Platforms, and later
2323
- Intel® Xeon® E3
2424
- Intel® NUC Kit NUC7CJYH
2525

@@ -39,10 +39,16 @@ The SGX plugin can take a number of command line arguments, summarised in the fo
3939
|:---- |:-------- |:------- |
4040
| -enclave-limit | int | the number of containers per worker node allowed to use `/dev/sgx_enclave` device node (default: `20`) |
4141
| -provision-limit | int | the number of containers per worker node allowed to use `/dev/sgx_provision` device node (default: `20`) |
42+
| -dcap-infra-resources | bool | a boolean opt-in flag to register special `qe` and `registration` resources for Intel Data Center Attestation Primitive (DCAP) containers (default: `false`) |
4243

4344
The plugin also accepts a number of other arguments related to logging. Please use the `-h` option to see
4445
the complete list of logging related options.
4546

47+
Note: `qe` and `registration` resources are intended for a very specific use-case: every SGX enabled
48+
node gets only one such resource and they are consumed by a quoting daemon (e.g., `aesmd` or `tdx-qgs`)
49+
and a platform registration tool (e.g., PCK-ID-Retrieval-Tool), respectively. This is done so that
50+
these containers can run without any elevated privileges.
51+
4652
## Installation
4753

4854
The following sections cover how to use the necessary Kubernetes SGX specific

cmd/sgx_plugin/sgx_plugin.go

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
dpapi "github.com/intel/intel-device-plugins-for-kubernetes/pkg/deviceplugin"
2626
"k8s.io/klog/v2"
2727
pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
28+
cdispec "tags.cncf.io/container-device-interface/specs-go"
2829
)
2930

3031
const (
@@ -38,18 +39,20 @@ const (
3839
)
3940

4041
type devicePlugin struct {
41-
scanDone chan bool
42-
devfsDir string
43-
nEnclave uint
44-
nProvision uint
42+
scanDone chan bool
43+
devfsDir string
44+
nEnclave uint
45+
nProvision uint
46+
dcapInfraResources bool
4547
}
4648

47-
func newDevicePlugin(devfsDir string, nEnclave, nProvision uint) *devicePlugin {
49+
func newDevicePlugin(devfsDir string, nEnclave, nProvision uint, dcapInfraResources bool) *devicePlugin {
4850
return &devicePlugin{
49-
devfsDir: devfsDir,
50-
nEnclave: nEnclave,
51-
nProvision: nProvision,
52-
scanDone: make(chan bool, 1),
51+
devfsDir: devfsDir,
52+
nEnclave: nEnclave,
53+
nProvision: nProvision,
54+
dcapInfraResources: dcapInfraResources,
55+
scanDone: make(chan bool, 1),
5356
}
5457
}
5558

@@ -96,6 +99,43 @@ func (dp *devicePlugin) scan() (dpapi.DeviceTree, error) {
9699
devTree.AddDevice(deviceTypeProvision, devID, dpapi.NewDeviceInfoWithTopologyHints(pluginapi.Healthy, nodes, nil, nil, nil, nil, nil))
97100
}
98101

102+
if !dp.dcapInfraResources {
103+
return devTree, nil
104+
}
105+
106+
qeNodes := []pluginapi.DeviceSpec{
107+
{HostPath: sgxEnclavePath, ContainerPath: sgxEnclavePath, Permissions: "rw"},
108+
{HostPath: sgxProvisionPath, ContainerPath: sgxProvisionPath, Permissions: "rw"},
109+
}
110+
111+
devTree.AddDevice("qe", "qe-1", dpapi.NewDeviceInfoWithTopologyHints(pluginapi.Healthy, qeNodes, nil, nil, nil, nil, nil))
112+
113+
regNodes := []pluginapi.DeviceSpec{
114+
{HostPath: sgxEnclavePath, ContainerPath: sgxEnclavePath, Permissions: "rw"},
115+
{HostPath: sgxProvisionPath, ContainerPath: sgxProvisionPath, Permissions: "rw"},
116+
}
117+
118+
// /sys/firmware is a maskedPath (see OCI runtime spec.) set by runtimes so /sys/firmware/efi/efivars mount point cannot
119+
// be made visible to containers without running them as privileged. Here, efivarfs gets mounted to /run/efivars as native
120+
// efivarfs fs type (a bind mount would also work) to avoid elevated privileges (NB: efivarfs sets "non-standard" EFI variables
121+
// as "IMMUTABLE" so CAP_LINUX_IMMUTABLE capability is needed for write). Applications must be adapted to the containerPath set here.
122+
efiVarFsMount := &cdispec.Spec{
123+
Version: dpapi.CDIVersion,
124+
Kind: dpapi.CDIVendor + "/sgx",
125+
Devices: []cdispec.Device{
126+
{
127+
Name: "efivarfs",
128+
ContainerEdits: cdispec.ContainerEdits{
129+
Mounts: []*cdispec.Mount{
130+
{HostPath: "efivarfs", ContainerPath: "/run/efivars", Type: "efivarfs", Options: []string{"rw", "nosuid", "nodev", "noexec", "relatime"}},
131+
},
132+
},
133+
},
134+
},
135+
}
136+
137+
devTree.AddDevice("registration", "registration-1", dpapi.NewDeviceInfoWithTopologyHints(pluginapi.Healthy, regNodes, nil, nil, nil, nil, efiVarFsMount))
138+
99139
return devTree, nil
100140
}
101141

@@ -121,15 +161,18 @@ func getDefaultPodCount(nCPUs uint) uint {
121161
func main() {
122162
var enclaveLimit, provisionLimit uint
123163

164+
var dcapInfraResources bool
165+
124166
podCount := getDefaultPodCount(uint(runtime.NumCPU()))
125167

126168
flag.UintVar(&enclaveLimit, "enclave-limit", podCount, "Number of \"enclave\" resources")
127169
flag.UintVar(&provisionLimit, "provision-limit", podCount, "Number of \"provision\" resources")
170+
flag.BoolVar(&dcapInfraResources, "dcap-infra-resources", false, "Register special resources for Intel DCAP infrastructure containers")
128171
flag.Parse()
129172

130173
klog.V(4).Infof("SGX device plugin started with %d \"%s/enclave\" resources and %d \"%s/provision\" resources.", enclaveLimit, namespace, provisionLimit, namespace)
131174

132-
plugin := newDevicePlugin(devicePath, enclaveLimit, provisionLimit)
175+
plugin := newDevicePlugin(devicePath, enclaveLimit, provisionLimit, dcapInfraResources)
133176
manager := dpapi.NewManager(namespace, plugin)
134177
manager.Run()
135178
}

cmd/sgx_plugin/sgx_plugin_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,22 @@ func init() {
2727
_ = flag.Set("v", "4") // Enable debug output
2828
}
2929

30+
// Update if new resource types are added.
31+
const dcapInfraResources = 2
32+
3033
// mockNotifier implements Notifier interface.
3134
type mockNotifier struct {
3235
scanDone chan bool
3336
enclaveDevCount int
3437
provisionDevCount int
38+
dcapInfraResCnt int
3539
}
3640

3741
// Notify stops plugin Scan.
3842
func (n *mockNotifier) Notify(newDeviceTree dpapi.DeviceTree) {
3943
n.enclaveDevCount = len(newDeviceTree[deviceTypeEnclave])
4044
n.provisionDevCount = len(newDeviceTree[deviceTypeProvision])
45+
n.dcapInfraResCnt = len(newDeviceTree) - n.enclaveDevCount - n.provisionDevCount
4146
n.scanDone <- true
4247
}
4348

@@ -95,6 +100,7 @@ func TestScan(t *testing.T) {
95100
requestedProvisionDevs uint
96101
expectedEnclaveDevs int
97102
expectedProvisionDevs int
103+
requestDcapInfra bool
98104
}{
99105
{
100106
name: "no device installed",
@@ -131,6 +137,16 @@ func TestScan(t *testing.T) {
131137
requestedProvisionDevs: 20,
132138
expectedProvisionDevs: 20,
133139
},
140+
{
141+
name: "all resources",
142+
enclaveDevice: "sgx_enclave",
143+
provisionDevice: "sgx_provision",
144+
requestedEnclaveDevs: 1,
145+
expectedEnclaveDevs: 1,
146+
requestedProvisionDevs: 1,
147+
expectedProvisionDevs: 1,
148+
requestDcapInfra: true,
149+
},
134150
}
135151

136152
for _, tc := range tcases {
@@ -159,7 +175,7 @@ func TestScan(t *testing.T) {
159175
}
160176
}
161177

162-
plugin := newDevicePlugin(devfs, tc.requestedEnclaveDevs, tc.requestedProvisionDevs)
178+
plugin := newDevicePlugin(devfs, tc.requestedEnclaveDevs, tc.requestedProvisionDevs, tc.requestDcapInfra)
163179

164180
notifier := &mockNotifier{
165181
scanDone: plugin.scanDone,
@@ -175,6 +191,9 @@ func TestScan(t *testing.T) {
175191
if tc.expectedProvisionDevs != notifier.provisionDevCount {
176192
t.Errorf("Wrong number of discovered provision devices")
177193
}
194+
if tc.requestDcapInfra && notifier.dcapInfraResCnt != dcapInfraResources {
195+
t.Errorf("Wrong number of discovered DCAP infra resources: expected %d, got %d.", dcapInfraResources, notifier.dcapInfraResCnt)
196+
}
178197
})
179198
}
180199
}

deployments/operator/crd/bases/deviceplugin.intel.com_sgxdeviceplugins.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ spec:
5555
spec:
5656
description: SgxDevicePluginSpec defines the desired state of SgxDevicePlugin.
5757
properties:
58+
dcapInfraResources:
59+
description: DcapInfraResources flag enables two special resources
60+
for Intel DCAP infrastructure containers.
61+
type: boolean
5862
enclaveLimit:
5963
description: EnclaveLimit is a number of containers that can share
6064
the same SGX enclave device.

deployments/sgx_plugin/base/intel-sgx-plugin.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ spec:
4949
- name: sgx-provision
5050
mountPath: /dev/sgx_provision
5151
readOnly: true
52+
- name: cdipath
53+
mountPath: /var/run/cdi
5254
volumes:
5355
- name: kubeletsockets
5456
hostPath:
@@ -61,5 +63,9 @@ spec:
6163
hostPath:
6264
path: /dev/sgx_provision
6365
type: CharDevice
66+
- name: cdipath
67+
hostPath:
68+
path: /var/run/cdi
69+
type: DirectoryOrCreate
6470
nodeSelector:
6571
kubernetes.io/arch: amd64

pkg/apis/deviceplugin/v1/sgxdeviceplugin_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ type SgxDevicePluginSpec struct {
4646
// +kubebuilder:validation:Minimum=1
4747
ProvisionLimit int `json:"provisionLimit,omitempty"`
4848

49+
// DcapInfraResources flag enables two special resources for Intel DCAP infrastructure containers.
50+
DcapInfraResources bool `json:"dcapInfraResources,omitempty"`
51+
4952
// LogLevel sets the plugin's log level.
5053
// +kubebuilder:validation:Minimum=0
5154
LogLevel int `json:"logLevel,omitempty"`

pkg/controllers/sgx/controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,5 +247,9 @@ func getPodArgs(sdp *devicepluginv1.SgxDevicePlugin) []string {
247247
args = append(args, "-provision-limit", "1")
248248
}
249249

250+
if sdp.Spec.DcapInfraResources {
251+
args = append(args, "-dcap-infra-resources")
252+
}
253+
250254
return args
251255
}

pkg/controllers/sgx/controller_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet
3939

4040
yes := true
4141
no := false
42+
directoryOrCreate := v1.HostPathDirectoryOrCreate
4243
charDevice := v1.HostPathCharDev
4344
maxUnavailable := intstr.FromInt(1)
4445
maxSurge := intstr.FromInt(0)
@@ -116,6 +117,10 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet
116117
MountPath: "/dev/sgx_provision",
117118
ReadOnly: true,
118119
},
120+
{
121+
Name: "cdipath",
122+
MountPath: "/var/run/cdi",
123+
},
119124
},
120125
},
121126
},
@@ -147,6 +152,15 @@ func (c *controller) newDaemonSetExpected(rawObj client.Object) *apps.DaemonSet
147152
},
148153
},
149154
},
155+
{
156+
Name: "cdipath",
157+
VolumeSource: v1.VolumeSource{
158+
HostPath: &v1.HostPathVolumeSource{
159+
Path: "/var/run/cdi",
160+
Type: &directoryOrCreate,
161+
},
162+
},
163+
},
150164
},
151165
},
152166
},

test/envtest/sgxdeviceplugin_controller_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
8181
updatedLogLevel := 2
8282
updatedEnclaveLimit := 2
8383
updatedProvisionLimit := 2
84+
updatedDcapInfra := true
8485
updatedNodeSelector := map[string]string{"updated-sgx-nodeselector": "true"}
8586

8687
fetched.Spec.Image = updatedImage
@@ -89,6 +90,7 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
8990
fetched.Spec.EnclaveLimit = updatedEnclaveLimit
9091
fetched.Spec.ProvisionLimit = updatedProvisionLimit
9192
fetched.Spec.NodeSelector = updatedNodeSelector
93+
fetched.Spec.DcapInfraResources = updatedDcapInfra
9294

9395
Expect(k8sClient.Update(context.Background(), fetched)).Should(Succeed())
9496
fetchedUpdated := &devicepluginv1.SgxDevicePlugin{}
@@ -109,6 +111,7 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
109111
strconv.Itoa(updatedEnclaveLimit),
110112
"-provision-limit",
111113
strconv.Itoa(updatedProvisionLimit),
114+
"-dcap-infra-resources",
112115
}
113116

114117
Expect(ds.Spec.Template.Spec.Containers[0].Args).Should(ConsistOf(expectArgs))

0 commit comments

Comments
 (0)