Skip to content

Commit bd4a12f

Browse files
authored
Feature: pod security admission (#165)
* Update k8s libraries to v0.26.1 Signed-off-by: Philippe Martin <[email protected]> * Run tests with go 1.19 Signed-off-by: Philippe Martin <[email protected]> * Fix fmt with go1.19 Signed-off-by: Philippe Martin <[email protected]> * Update Check license for go 1.19 Signed-off-by: Philippe Martin <[email protected]> * Add GetPodTemplateSpec to build the complete PodTemplateSpec (to replace calls to GetContainers + GetInitContainers) Signed-off-by: Philippe Martin <[email protected]> * Adapt unit tests Signed-off-by: Philippe Martin <[email protected]> * Move container and pod overrides from GetAllContainers/getPodTemplateSpec to GetPodTemplateSpec Signed-off-by: Philippe Martin <[email protected]> * Add unit tests for GetPodTemplateSpec Signed-off-by: Philippe Martin <[email protected]> * Add Policy parameter to PodTemplateParams Signed-off-by: Philippe Martin <[email protected]> * Policies Signed-off-by: Philippe Martin <[email protected]> * Add deprecation information Signed-off-by: Philippe Martin <[email protected]> * Review Signed-off-by: Philippe Martin <[email protected]> * Update go version fo codecov Signed-off-by: Philippe Martin <[email protected]> * Review: factorize some duplicate code Signed-off-by: Philippe Martin <[email protected]> --------- Signed-off-by: Philippe Martin <[email protected]>
1 parent 539d4b1 commit bd4a12f

File tree

17 files changed

+1234
-310
lines changed

17 files changed

+1234
-310
lines changed

.github/workflows/codecov.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Set up Go 1.x
1515
uses: actions/setup-go@v2
1616
with:
17-
go-version: 1.17
17+
go-version: 1.19
1818
- name: Run tests
1919
run: make test
2020
- name: Codecov

.github/workflows/go.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Setup Go environment
1717
uses: actions/[email protected]
1818
with:
19-
go-version: 1.16
19+
go-version: 1.19
2020
id: go
2121

2222
- name: Check out code into the Go module directory
@@ -45,7 +45,7 @@ jobs:
4545
4646
- name: Check license
4747
run: |
48-
go get github.com/google/addlicense@latest
48+
go install github.com/google/addlicense@latest
4949
git reset HEAD --hard
5050
make check_license
5151
if [[ $? != 0 ]]

go.mod

+11-10
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@ require (
66
github.com/devfile/api/v2 v2.2.0
77
github.com/devfile/registry-support/registry-library v0.0.0-20221018213054-47b3ffaeadba
88
github.com/fatih/color v1.7.0
9-
github.com/fsnotify/fsnotify v1.4.9
9+
github.com/fsnotify/fsnotify v1.6.0
1010
github.com/go-git/go-git/v5 v5.4.2
1111
github.com/gobwas/glob v0.2.3
1212
github.com/golang/mock v1.6.0
13-
github.com/google/go-cmp v0.5.6
13+
github.com/google/go-cmp v0.5.9
1414
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
1515
github.com/hashicorp/go-multierror v1.1.1
1616
github.com/hashicorp/go-version v1.4.0
1717
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
1818
github.com/openshift/api v0.0.0-20200930075302-db52bc4ef99f
1919
github.com/pkg/errors v0.9.1
2020
github.com/spf13/afero v1.6.0
21-
github.com/stretchr/testify v1.7.0
21+
github.com/stretchr/testify v1.8.0
2222
github.com/xeipuuv/gojsonschema v1.2.0
2323
gopkg.in/yaml.v3 v3.0.1
24-
k8s.io/api v0.21.3
25-
k8s.io/apiextensions-apiserver v0.21.3
26-
k8s.io/apimachinery v0.21.3
27-
k8s.io/client-go v0.21.3
24+
k8s.io/api v0.26.1
25+
k8s.io/apiextensions-apiserver v0.26.1
26+
k8s.io/apimachinery v0.26.1
27+
k8s.io/client-go v0.26.1
2828
k8s.io/klog v1.0.0
29-
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471
30-
sigs.k8s.io/controller-runtime v0.9.5
31-
sigs.k8s.io/yaml v1.2.0
29+
k8s.io/pod-security-admission v0.26.1
30+
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
31+
sigs.k8s.io/controller-runtime v0.14.4
32+
sigs.k8s.io/yaml v1.3.0
3233
)

go.sum

+302-52
Large diffs are not rendered by default.

pkg/devfile/generator/generators.go

+141-20
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package generator
1717

1818
import (
19+
"errors"
1920
"fmt"
2021

2122
"github.com/devfile/api/v2/pkg/attributes"
@@ -34,6 +35,7 @@ import (
3435
networkingv1 "k8s.io/api/networking/v1"
3536
"k8s.io/apimachinery/pkg/api/resource"
3637
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38+
psaapi "k8s.io/pod-security-admission/api"
3739
)
3840

3941
const (
@@ -74,6 +76,8 @@ func GetObjectMeta(name, namespace string, labels, annotations map[string]string
7476
}
7577

7678
// GetContainers iterates through all container components, filters out init containers and returns corresponding containers
79+
//
80+
// Deprecated: in favor of GetPodTemplateSpec
7781
func GetContainers(devfileObj parser.DevfileObj, options common.DevfileOptions) ([]corev1.Container, error) {
7882
allContainers, err := getAllContainers(devfileObj, options)
7983
if err != nil {
@@ -120,6 +124,8 @@ func GetContainers(devfileObj parser.DevfileObj, options common.DevfileOptions)
120124
}
121125

122126
// GetInitContainers gets the init container for every preStart devfile event
127+
//
128+
// Deprecated: in favor of GetPodTemplateSpec
123129
func GetInitContainers(devfileObj parser.DevfileObj) ([]corev1.Container, error) {
124130
containers, err := getAllContainers(devfileObj, common.DevfileOptions{})
125131
if err != nil {
@@ -170,23 +176,93 @@ func GetInitContainers(devfileObj parser.DevfileObj) ([]corev1.Container, error)
170176

171177
// DeploymentParams is a struct that contains the required data to create a deployment object
172178
type DeploymentParams struct {
173-
TypeMeta metav1.TypeMeta
174-
ObjectMeta metav1.ObjectMeta
175-
InitContainers []corev1.Container
176-
Containers []corev1.Container
179+
TypeMeta metav1.TypeMeta
180+
ObjectMeta metav1.ObjectMeta
181+
// Deprecated: InitContainers, Containers and Volumes are deprecated and are replaced by PodTemplateSpec.
182+
// A PodTemplateSpec value can be obtained calling GetPodTemplateSpec function, instead of calling GetContainers and GetInitContainers
183+
InitContainers []corev1.Container
184+
// Deprecated: see InitContainers
185+
Containers []corev1.Container
186+
// Deprecated: see InitContainers
177187
Volumes []corev1.Volume
188+
PodTemplateSpec *corev1.PodTemplateSpec
178189
PodSelectorLabels map[string]string
179190
Replicas *int32
180191
}
181192

182193
// GetDeployment gets a deployment object
183194
func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams) (*appsv1.Deployment, error) {
184195

196+
deploySpecParams := deploymentSpecParams{
197+
PodSelectorLabels: deployParams.PodSelectorLabels,
198+
Replicas: deployParams.Replicas,
199+
}
200+
if deployParams.PodTemplateSpec == nil {
201+
// Deprecated
202+
podTemplateSpecParams := podTemplateSpecParams{
203+
ObjectMeta: deployParams.ObjectMeta,
204+
InitContainers: deployParams.InitContainers,
205+
Containers: deployParams.Containers,
206+
Volumes: deployParams.Volumes,
207+
}
208+
podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams)
209+
if err != nil {
210+
return nil, err
211+
}
212+
deploySpecParams.PodTemplateSpec = *podTemplateSpec
213+
} else {
214+
if len(deployParams.InitContainers) > 0 ||
215+
len(deployParams.Containers) > 0 ||
216+
len(deployParams.Volumes) > 0 {
217+
return nil, errors.New("InitContainers, Containers and Volumes cannot be set when PodTemplateSpec is set in parameters")
218+
}
219+
220+
deploySpecParams.PodTemplateSpec = *deployParams.PodTemplateSpec
221+
}
222+
223+
containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{})
224+
if err != nil {
225+
return nil, err
226+
}
227+
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment)
228+
229+
deployment := &appsv1.Deployment{
230+
TypeMeta: deployParams.TypeMeta,
231+
ObjectMeta: deployParams.ObjectMeta,
232+
Spec: *getDeploymentSpec(deploySpecParams),
233+
}
234+
235+
return deployment, nil
236+
}
237+
238+
// PodTemplateParams is a struct that contains the required data to create a podtemplatespec object
239+
type PodTemplateParams struct {
240+
ObjectMeta metav1.ObjectMeta
241+
// PodSecurityAdmissionPolicy is the policy to be respected by the created pod
242+
// The pod will be patched, if necessary, to respect the policies
243+
PodSecurityAdmissionPolicy psaapi.Policy
244+
}
245+
246+
// GetPodTemplateSpec returns a pod template
247+
// The function:
248+
// - iterates through all container components, filters out init containers and gets corresponding containers
249+
// - gets the init container for every preStart devfile event
250+
// - patches the pod template and containers to satisfy PodSecurityAdmissionPolicy
251+
// - patches the pod template and containers to apply pod and container overrides
252+
func GetPodTemplateSpec(devfileObj parser.DevfileObj, podTemplateParams PodTemplateParams) (*corev1.PodTemplateSpec, error) {
253+
containers, err := GetContainers(devfileObj, common.DevfileOptions{})
254+
if err != nil {
255+
return nil, err
256+
}
257+
initContainers, err := GetInitContainers(devfileObj)
258+
if err != nil {
259+
return nil, err
260+
}
261+
185262
podTemplateSpecParams := podTemplateSpecParams{
186-
ObjectMeta: deployParams.ObjectMeta,
187-
InitContainers: deployParams.InitContainers,
188-
Containers: deployParams.Containers,
189-
Volumes: deployParams.Volumes,
263+
ObjectMeta: podTemplateParams.ObjectMeta,
264+
InitContainers: initContainers,
265+
Containers: containers,
190266
}
191267
var globalAttributes attributes.Attributes
192268
// attributes is not supported in versions less than 2.1.0, so we skip it
@@ -199,29 +275,74 @@ func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams)
199275
if err != nil {
200276
return nil, err
201277
}
202-
podTemplateSpec, err := getPodTemplateSpec(globalAttributes, components, podTemplateSpecParams)
278+
279+
podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams)
203280
if err != nil {
204281
return nil, err
205282
}
206-
deploySpecParams := deploymentSpecParams{
207-
PodTemplateSpec: *podTemplateSpec,
208-
PodSelectorLabels: deployParams.PodSelectorLabels,
209-
Replicas: deployParams.Replicas,
283+
284+
podTemplateSpec, err = patchForPolicy(podTemplateSpec, podTemplateParams.PodSecurityAdmissionPolicy)
285+
if err != nil {
286+
return nil, err
210287
}
211288

212-
containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{})
289+
if needsPodOverrides(globalAttributes, components) {
290+
patchedPodTemplateSpec, err := applyPodOverrides(globalAttributes, components, podTemplateSpec)
291+
if err != nil {
292+
return nil, err
293+
}
294+
patchedPodTemplateSpec.ObjectMeta = podTemplateSpecParams.ObjectMeta
295+
podTemplateSpec = patchedPodTemplateSpec
296+
}
297+
298+
podTemplateSpec.Spec.Containers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.Containers)
299+
if err != nil {
300+
return nil, err
301+
}
302+
podTemplateSpec.Spec.InitContainers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.InitContainers)
213303
if err != nil {
214304
return nil, err
215305
}
216-
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment)
217306

218-
deployment := &appsv1.Deployment{
219-
TypeMeta: deployParams.TypeMeta,
220-
ObjectMeta: deployParams.ObjectMeta,
221-
Spec: *getDeploymentSpec(deploySpecParams),
307+
return podTemplateSpec, nil
308+
}
309+
310+
func applyContainerOverrides(devfileObj parser.DevfileObj, containers []corev1.Container) ([]corev1.Container, error) {
311+
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{
312+
ComponentOptions: common.ComponentOptions{
313+
ComponentType: v1.ContainerComponentType,
314+
},
315+
})
316+
if err != nil {
317+
return nil, err
222318
}
223319

224-
return deployment, nil
320+
getContainerByName := func(name string) (*corev1.Container, bool) {
321+
for _, container := range containers {
322+
if container.Name == name {
323+
return &container, true
324+
}
325+
}
326+
return nil, false
327+
}
328+
329+
result := make([]corev1.Container, 0, len(containers))
330+
for _, comp := range containerComponents {
331+
container, found := getContainerByName(comp.Name)
332+
if !found {
333+
continue
334+
}
335+
if comp.Attributes.Exists(ContainerOverridesAttribute) {
336+
patched, err := containerOverridesHandler(comp, container)
337+
if err != nil {
338+
return nil, err
339+
}
340+
result = append(result, *patched)
341+
} else {
342+
result = append(result, *container)
343+
}
344+
}
345+
return result, nil
225346
}
226347

227348
// PVCParams is a struct to create PVC

0 commit comments

Comments
 (0)