Skip to content

Commit

Permalink
Feature: pod security admission (#165)
Browse files Browse the repository at this point in the history
* Update k8s libraries to v0.26.1

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Run tests with go 1.19

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Fix fmt with go1.19

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Update Check license for go 1.19

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Add GetPodTemplateSpec to build the complete PodTemplateSpec (to replace calls to GetContainers + GetInitContainers)

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Adapt unit tests

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Move container and pod overrides from GetAllContainers/getPodTemplateSpec to GetPodTemplateSpec

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Add unit tests for GetPodTemplateSpec

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Add Policy parameter to PodTemplateParams

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Policies

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Add deprecation information

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Review

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Update go version fo codecov

Signed-off-by: Philippe Martin <phmartin@redhat.com>

* Review: factorize some duplicate code

Signed-off-by: Philippe Martin <phmartin@redhat.com>

---------

Signed-off-by: Philippe Martin <phmartin@redhat.com>
  • Loading branch information
feloy authored Mar 8, 2023
1 parent 539d4b1 commit bd4a12f
Show file tree
Hide file tree
Showing 17 changed files with 1,234 additions and 310 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.19
- name: Run tests
run: make test
- name: Codecov
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Setup Go environment
uses: actions/setup-go@v2.1.3
with:
go-version: 1.16
go-version: 1.19
id: go

- name: Check out code into the Go module directory
Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:
- name: Check license
run: |
go get github.com/google/addlicense@latest
go install github.com/google/addlicense@latest
git reset HEAD --hard
make check_license
if [[ $? != 0 ]]
Expand Down
21 changes: 11 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,28 @@ require (
github.com/devfile/api/v2 v2.2.0
github.com/devfile/registry-support/registry-library v0.0.0-20221018213054-47b3ffaeadba
github.com/fatih/color v1.7.0
github.com/fsnotify/fsnotify v1.4.9
github.com/fsnotify/fsnotify v1.6.0
github.com/go-git/go-git/v5 v5.4.2
github.com/gobwas/glob v0.2.3
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.6
github.com/google/go-cmp v0.5.9
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.4.0
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
github.com/openshift/api v0.0.0-20200930075302-db52bc4ef99f
github.com/pkg/errors v0.9.1
github.com/spf13/afero v1.6.0
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.8.0
github.com/xeipuuv/gojsonschema v1.2.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.21.3
k8s.io/apiextensions-apiserver v0.21.3
k8s.io/apimachinery v0.21.3
k8s.io/client-go v0.21.3
k8s.io/api v0.26.1
k8s.io/apiextensions-apiserver v0.26.1
k8s.io/apimachinery v0.26.1
k8s.io/client-go v0.26.1
k8s.io/klog v1.0.0
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471
sigs.k8s.io/controller-runtime v0.9.5
sigs.k8s.io/yaml v1.2.0
k8s.io/pod-security-admission v0.26.1
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
sigs.k8s.io/controller-runtime v0.14.4
sigs.k8s.io/yaml v1.3.0
)
354 changes: 302 additions & 52 deletions go.sum

Large diffs are not rendered by default.

161 changes: 141 additions & 20 deletions pkg/devfile/generator/generators.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package generator

import (
"errors"
"fmt"

"github.com/devfile/api/v2/pkg/attributes"
Expand All @@ -34,6 +35,7 @@ import (
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
psaapi "k8s.io/pod-security-admission/api"
)

const (
Expand Down Expand Up @@ -74,6 +76,8 @@ func GetObjectMeta(name, namespace string, labels, annotations map[string]string
}

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

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

// DeploymentParams is a struct that contains the required data to create a deployment object
type DeploymentParams struct {
TypeMeta metav1.TypeMeta
ObjectMeta metav1.ObjectMeta
InitContainers []corev1.Container
Containers []corev1.Container
TypeMeta metav1.TypeMeta
ObjectMeta metav1.ObjectMeta
// Deprecated: InitContainers, Containers and Volumes are deprecated and are replaced by PodTemplateSpec.
// A PodTemplateSpec value can be obtained calling GetPodTemplateSpec function, instead of calling GetContainers and GetInitContainers
InitContainers []corev1.Container
// Deprecated: see InitContainers
Containers []corev1.Container
// Deprecated: see InitContainers
Volumes []corev1.Volume
PodTemplateSpec *corev1.PodTemplateSpec
PodSelectorLabels map[string]string
Replicas *int32
}

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

deploySpecParams := deploymentSpecParams{
PodSelectorLabels: deployParams.PodSelectorLabels,
Replicas: deployParams.Replicas,
}
if deployParams.PodTemplateSpec == nil {
// Deprecated
podTemplateSpecParams := podTemplateSpecParams{
ObjectMeta: deployParams.ObjectMeta,
InitContainers: deployParams.InitContainers,
Containers: deployParams.Containers,
Volumes: deployParams.Volumes,
}
podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams)
if err != nil {
return nil, err
}
deploySpecParams.PodTemplateSpec = *podTemplateSpec
} else {
if len(deployParams.InitContainers) > 0 ||
len(deployParams.Containers) > 0 ||
len(deployParams.Volumes) > 0 {
return nil, errors.New("InitContainers, Containers and Volumes cannot be set when PodTemplateSpec is set in parameters")
}

deploySpecParams.PodTemplateSpec = *deployParams.PodTemplateSpec
}

containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{})
if err != nil {
return nil, err
}
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment)

deployment := &appsv1.Deployment{
TypeMeta: deployParams.TypeMeta,
ObjectMeta: deployParams.ObjectMeta,
Spec: *getDeploymentSpec(deploySpecParams),
}

return deployment, nil
}

// PodTemplateParams is a struct that contains the required data to create a podtemplatespec object
type PodTemplateParams struct {
ObjectMeta metav1.ObjectMeta
// PodSecurityAdmissionPolicy is the policy to be respected by the created pod
// The pod will be patched, if necessary, to respect the policies
PodSecurityAdmissionPolicy psaapi.Policy
}

// GetPodTemplateSpec returns a pod template
// The function:
// - iterates through all container components, filters out init containers and gets corresponding containers
// - gets the init container for every preStart devfile event
// - patches the pod template and containers to satisfy PodSecurityAdmissionPolicy
// - patches the pod template and containers to apply pod and container overrides
func GetPodTemplateSpec(devfileObj parser.DevfileObj, podTemplateParams PodTemplateParams) (*corev1.PodTemplateSpec, error) {
containers, err := GetContainers(devfileObj, common.DevfileOptions{})
if err != nil {
return nil, err
}
initContainers, err := GetInitContainers(devfileObj)
if err != nil {
return nil, err
}

podTemplateSpecParams := podTemplateSpecParams{
ObjectMeta: deployParams.ObjectMeta,
InitContainers: deployParams.InitContainers,
Containers: deployParams.Containers,
Volumes: deployParams.Volumes,
ObjectMeta: podTemplateParams.ObjectMeta,
InitContainers: initContainers,
Containers: containers,
}
var globalAttributes attributes.Attributes
// attributes is not supported in versions less than 2.1.0, so we skip it
Expand All @@ -199,29 +275,74 @@ func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams)
if err != nil {
return nil, err
}
podTemplateSpec, err := getPodTemplateSpec(globalAttributes, components, podTemplateSpecParams)

podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams)
if err != nil {
return nil, err
}
deploySpecParams := deploymentSpecParams{
PodTemplateSpec: *podTemplateSpec,
PodSelectorLabels: deployParams.PodSelectorLabels,
Replicas: deployParams.Replicas,

podTemplateSpec, err = patchForPolicy(podTemplateSpec, podTemplateParams.PodSecurityAdmissionPolicy)
if err != nil {
return nil, err
}

containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{})
if needsPodOverrides(globalAttributes, components) {
patchedPodTemplateSpec, err := applyPodOverrides(globalAttributes, components, podTemplateSpec)
if err != nil {
return nil, err
}
patchedPodTemplateSpec.ObjectMeta = podTemplateSpecParams.ObjectMeta
podTemplateSpec = patchedPodTemplateSpec
}

podTemplateSpec.Spec.Containers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.Containers)
if err != nil {
return nil, err
}
podTemplateSpec.Spec.InitContainers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.InitContainers)
if err != nil {
return nil, err
}
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment)

deployment := &appsv1.Deployment{
TypeMeta: deployParams.TypeMeta,
ObjectMeta: deployParams.ObjectMeta,
Spec: *getDeploymentSpec(deploySpecParams),
return podTemplateSpec, nil
}

func applyContainerOverrides(devfileObj parser.DevfileObj, containers []corev1.Container) ([]corev1.Container, error) {
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{
ComponentOptions: common.ComponentOptions{
ComponentType: v1.ContainerComponentType,
},
})
if err != nil {
return nil, err
}

return deployment, nil
getContainerByName := func(name string) (*corev1.Container, bool) {
for _, container := range containers {
if container.Name == name {
return &container, true
}
}
return nil, false
}

result := make([]corev1.Container, 0, len(containers))
for _, comp := range containerComponents {
container, found := getContainerByName(comp.Name)
if !found {
continue
}
if comp.Attributes.Exists(ContainerOverridesAttribute) {
patched, err := containerOverridesHandler(comp, container)
if err != nil {
return nil, err
}
result = append(result, *patched)
} else {
result = append(result, *container)
}
}
return result, nil
}

// PVCParams is a struct to create PVC
Expand Down
Loading

0 comments on commit bd4a12f

Please sign in to comment.