Skip to content

Commit 498fe1d

Browse files
committed
sgx: set epc limits via NRI annotations
Signed-off-by: Mikko Ylinen <[email protected]>
1 parent de1f592 commit 498fe1d

File tree

9 files changed

+103
-0
lines changed

9 files changed

+103
-0
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ spec:
7878
description: NodeSelector provides a simple way to constrain device
7979
plugin pods to nodes with particular labels.
8080
type: object
81+
nriImage:
82+
description: 'NRIImage is a container image with SGX Node Resource
83+
Interface (NRI) plugin executable. Set this value if SGX EPC cgroups
84+
limits enforcement is wanted. TODO: is this a good name?'
85+
type: string
8186
provisionLimit:
8287
description: ProvisionLimit is a number of containers that can share
8388
the same SGX provision device.

deployments/operator/samples/deviceplugin_v1_sgxdeviceplugin.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ metadata:
44
name: sgxdeviceplugin-sample
55
spec:
66
image: intel/intel-sgx-plugin:0.29.0
7+
nriImage: ghcr.io/containers/nri-plugins/nri-sgx-epc:v0.3.2
78
enclaveLimit: 110
89
provisionLimit: 110
910
logLevel: 4
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resources:
2+
- ../../base
3+
4+
patches:
5+
- path: nri_plugin_patch.yaml
6+
target:
7+
name: intel-sgx-plugin
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: DaemonSet
3+
metadata:
4+
name: intel-sgx-plugin
5+
spec:
6+
template:
7+
spec:
8+
containers:
9+
- name: nri-sgx-epc
10+
image: ghcr.io/containers/nri-plugins/nri-sgx-epc:unstable
11+
securityContext:
12+
readOnlyRootFilesystem: true
13+
allowPrivilegeEscalation: false
14+
imagePullPolicy: IfNotPresent
15+
volumeMounts:
16+
- name: nrisockets
17+
mountPath: /var/run/nri
18+
volumes:
19+
- name: nrisockets
20+
hostPath:
21+
path: /var/run/nri

pkg/apis/deviceplugin/v1/sgxdeviceplugin_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ type SgxDevicePluginSpec struct {
3838
// Specialized nodes (e.g., with accelerators) can be Tainted to make sure unwanted pods are not scheduled on them. Tolerations can be set for the plugin pod to neutralize the Taint.
3939
Tolerations []v1.Toleration `json:"tolerations,omitempty"`
4040

41+
// NRIImage is a container image with SGX Node Resource Interface (NRI) plugin executable. Set
42+
// this value if SGX EPC cgroups limits enforcement is wanted.
43+
// TODO: is this a good name?
44+
NRIImage string `json:"nriImage,omitempty"`
45+
4146
// EnclaveLimit is a number of containers that can share the same SGX enclave device.
4247
// +kubebuilder:validation:Minimum=1
4348
EnclaveLimit int `json:"enclaveLimit,omitempty"`

pkg/controllers/sgx/controller.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,27 @@ func setInitContainer(spec *v1.PodSpec, imageName string) {
112112
addVolumeIfMissing(spec, "nfd-features", "/etc/kubernetes/node-feature-discovery/source.d/", v1.HostPathDirectoryOrCreate)
113113
}
114114

115+
func setNRIContainer(spec *v1.PodSpec, imageName string) {
116+
yes := true
117+
no := false
118+
spec.Containers = append(spec.Containers, v1.Container{
119+
Name: "nri-sgx-epc",
120+
Image: imageName,
121+
ImagePullPolicy: "IfNotPresent",
122+
SecurityContext: &v1.SecurityContext{
123+
ReadOnlyRootFilesystem: &yes,
124+
AllowPrivilegeEscalation: &no,
125+
},
126+
VolumeMounts: []v1.VolumeMount{
127+
{
128+
Name: "nrisockets",
129+
MountPath: "/var/run/nri",
130+
},
131+
},
132+
})
133+
addVolumeIfMissing(spec, "nrisockets", "/var/run/nri", v1.HostPathDirectoryOrCreate)
134+
}
135+
115136
func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet {
116137
devicePlugin := rawObj.(*devicepluginv1.SgxDevicePlugin)
117138

@@ -135,6 +156,10 @@ func (c *controller) NewDaemonSet(rawObj client.Object) *apps.DaemonSet {
135156
if devicePlugin.Spec.InitImage != "" {
136157
setInitContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.InitImage)
137158
}
159+
// add the optional NRI plugin container
160+
if devicePlugin.Spec.NRIImage != "" {
161+
setNRIContainer(&daemonSet.Spec.Template.Spec, devicePlugin.Spec.NRIImage)
162+
}
138163

139164
return daemonSet
140165
}
@@ -170,6 +195,26 @@ func (c *controller) UpdateDaemonSet(rawObj client.Object, ds *apps.DaemonSet) (
170195
updated = true
171196
}
172197

198+
// remove NRI plugin
199+
if len(ds.Spec.Template.Spec.Containers) > 1 && dp.Spec.NRIImage == "" {
200+
ds.Spec.Template.Spec.Containers = []v1.Container{ds.Spec.Template.Spec.Containers[0]}
201+
ds.Spec.Template.Spec.Volumes = removeVolume(ds.Spec.Template.Spec.Volumes, "nrisockets")
202+
updated = true
203+
}
204+
205+
// update NRI plugin image
206+
if len(ds.Spec.Template.Spec.Containers) > 1 && ds.Spec.Template.Spec.Containers[1].Image != dp.Spec.NRIImage {
207+
ds.Spec.Template.Spec.Containers[1].Image = dp.Spec.NRIImage
208+
updated = true
209+
}
210+
211+
// add NRI plugin image
212+
if len(ds.Spec.Template.Spec.Containers) == 1 && dp.Spec.NRIImage != "" {
213+
setNRIContainer(&ds.Spec.Template.Spec, dp.Spec.NRIImage)
214+
215+
updated = true
216+
}
217+
173218
if len(dp.Spec.NodeSelector) > 0 {
174219
if !reflect.DeepEqual(ds.Spec.Template.Spec.NodeSelector, dp.Spec.NodeSelector) {
175220
ds.Spec.Template.Spec.NodeSelector = dp.Spec.NodeSelector

pkg/webhooks/sgx/sgx.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func (s *Mutator) SetupWebhookWithManager(mgr ctrl.Manager) error {
4343
}
4444

4545
const (
46+
epcLimitKey = "epc-limit.nri.io/container"
4647
namespace = "sgx.intel.com"
4748
encl = namespace + "/enclave"
4849
epc = namespace + "/epc"
@@ -156,6 +157,8 @@ func (s *Mutator) Default(ctx context.Context, obj runtime.Object) error {
156157
continue
157158
}
158159

160+
pod.Annotations[fmt.Sprintf("%s.%s", epcLimitKey, container.Name)] = fmt.Sprintf("%d", epcSize)
161+
159162
totalEpc += epcSize
160163

161164
// Quote Generation Modes:

test/e2e/sgxadmissionwebhook/sgxaadmissionwebhook.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func describe() {
6969

7070
ginkgo.By("checking the pod total EPC size annotation is correctly set")
7171
gomega.Expect(pod.Annotations["sgx.intel.com/epc"]).To(gomega.Equal("1Mi"))
72+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test"]).To(gomega.Equal("1048576"))
7273
})
7374
ginkgo.It("mutates created pods when the container contains the quote generation libraries", func(ctx context.Context) {
7475
ginkgo.By("submitting the pod")
@@ -79,6 +80,7 @@ func describe() {
7980

8081
ginkgo.By("checking the pod total EPC size annotation is correctly set")
8182
gomega.Expect(pod.Annotations["sgx.intel.com/epc"]).To(gomega.Equal("1Mi"))
83+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test"]).To(gomega.Equal("1048576"))
8284
})
8385
ginkgo.It("mutates created pods when the container uses aesmd from a side-car container to generate quotes", func(ctx context.Context) {
8486
ginkgo.By("submitting the pod")
@@ -93,6 +95,8 @@ func describe() {
9395
gomega.Expect(pod.Spec.Containers[0].Env[0].Value).To(gomega.Equal("1"))
9496
ginkgo.By("checking the pod total EPC size annotation is correctly set")
9597
gomega.Expect(pod.Annotations["sgx.intel.com/epc"]).To(gomega.Equal("2Mi"))
98+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test"]).To(gomega.Equal("1048576"))
99+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.aesmd"]).To(gomega.Equal("1048576"))
96100
})
97101
ginkgo.It("mutates created pods where one container uses host/daemonset aesmd to generate quotes", func(ctx context.Context) {
98102
ginkgo.By("submitting the pod")
@@ -106,6 +110,7 @@ func describe() {
106110
gomega.Expect(pod.Spec.Containers[0].Env[0].Value).To(gomega.Equal("1"))
107111
ginkgo.By("checking the pod total EPC size annotation is correctly set")
108112
gomega.Expect(pod.Annotations["sgx.intel.com/epc"]).To(gomega.Equal("1Mi"))
113+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test"]).To(gomega.Equal("1048576"))
109114
})
110115
ginkgo.It("mutates created pods where three containers use host/daemonset aesmd to generate quotes", func(ctx context.Context) {
111116
ginkgo.By("submitting the pod")
@@ -125,6 +130,9 @@ func describe() {
125130
gomega.Expect(pod.Spec.Containers[2].Env[0].Value).To(gomega.Equal("1"))
126131
ginkgo.By("checking the pod total EPC size annotation is correctly set")
127132
gomega.Expect(pod.Annotations["sgx.intel.com/epc"]).To(gomega.Equal("3Mi"))
133+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test1"]).To(gomega.Equal("1048576"))
134+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test2"]).To(gomega.Equal("1048576"))
135+
gomega.Expect(pod.Annotations["epc-limit.nri.io/container.test3"]).To(gomega.Equal("1048576"))
128136
})
129137
ginkgo.It("checks that Volumes and VolumeMounts are created only once", func(ctx context.Context) {
130138
ginkgo.By("submitting the pod")

test/envtest/sgxdeviceplugin_controller_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
3939
spec := devicepluginv1.SgxDevicePluginSpec{
4040
Image: "sgx-testimage",
4141
InitImage: "sgx-testinitimage",
42+
NRIImage: "sgx-testnriimage",
4243
NodeSelector: map[string]string{"sgx-nodeselector": "true"},
4344
}
4445

@@ -78,13 +79,15 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
7879
By("updating SgxDevicePlugin successfully")
7980
updatedImage := "updated-sgx-testimage"
8081
updatedInitImage := "updated-sgx-testinitimage"
82+
updatedNRIImage := "updated-sgx-testnriimage"
8183
updatedLogLevel := 2
8284
updatedEnclaveLimit := 2
8385
updatedProvisionLimit := 2
8486
updatedNodeSelector := map[string]string{"updated-sgx-nodeselector": "true"}
8587

8688
fetched.Spec.Image = updatedImage
8789
fetched.Spec.InitImage = updatedInitImage
90+
fetched.Spec.NRIImage = updatedNRIImage
8891
fetched.Spec.LogLevel = updatedLogLevel
8992
fetched.Spec.EnclaveLimit = updatedEnclaveLimit
9093
fetched.Spec.ProvisionLimit = updatedProvisionLimit
@@ -114,13 +117,17 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
114117
Expect(ds.Spec.Template.Spec.Containers[0].Args).Should(ConsistOf(expectArgs))
115118
Expect(ds.Spec.Template.Spec.Containers[0].Image).Should(Equal(updatedImage))
116119
Expect(ds.Spec.Template.Spec.InitContainers).To(HaveLen(1))
120+
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(2))
121+
Expect(ds.Spec.Template.Spec.Containers[1].Image).Should(Equal(updatedNRIImage))
117122
Expect(ds.Spec.Template.Spec.InitContainers[0].Image).To(Equal(updatedInitImage))
118123
Expect(ds.Spec.Template.Spec.NodeSelector).Should(Equal(updatedNodeSelector))
119124

120125
By("updating SgxDevicePlugin with different values successfully")
121126
updatedInitImage = ""
127+
updatedNRIImage = ""
122128
updatedNodeSelector = map[string]string{}
123129
fetched.Spec.InitImage = updatedInitImage
130+
fetched.Spec.NRIImage = updatedNRIImage
124131
fetched.Spec.NodeSelector = updatedNodeSelector
125132

126133
Expect(k8sClient.Update(context.Background(), fetched)).Should(Succeed())
@@ -130,6 +137,7 @@ var _ = Describe("SgxDevicePlugin Controller", func() {
130137
err = k8sClient.Get(context.Background(), types.NamespacedName{Namespace: ns, Name: expectedDsName}, ds)
131138
Expect(err).To(BeNil())
132139
Expect(ds.Spec.Template.Spec.InitContainers).To(HaveLen(0))
140+
Expect(ds.Spec.Template.Spec.Containers).To(HaveLen(1))
133141
Expect(ds.Spec.Template.Spec.NodeSelector).Should(And(HaveLen(1), HaveKeyWithValue("kubernetes.io/arch", "amd64")))
134142

135143
By("updating SgxDevicePlugin with tolerations")

0 commit comments

Comments
 (0)