Implemented validation logic for the webhook (#593)

* Fix workflow for autogenerating docs (#592)

* Use grep -c flag in check for changes step to fix case when more than 1 website file was modified

* Implemented validation logic for the webhook
- Created a single Validate() function to validate both updating and creating Jenkins CR.
- Implemented the Validate function to fetch warnings from the API and do security check if
  being enabled.
- Updated the helm charts and helm-e2e target to run the helm tests.

* Configure bot for labelling new issues as needing triage (#597)

* Configure bot for managing stale issues (#598)

* Docs: explanation what is backed up and why (#599)

* Explanation what's backed up and why

* Auto-updated docs (#600)

Co-authored-by: prryb <prryb@users.noreply.github.com>

* Docs: clarification of description of get latest command in backup (#601)

* Auto-updated docs (#602)

Co-authored-by: Sig00rd <Sig00rd@users.noreply.github.com>

* Bump seedjobs agent image version to 4.9-1 (#604)

* Add GitLFS pull after checkout behaviour to SeedJob GroovyScript Template (#483)

Add GitLFS pull after checkout behaviour to support also repositories which are relying on Git LFS

Close #482

* Docs: minor fixes (#608)

* Link to project's DockerHub in README's section on nightly builds, add paragraph about nightly builds in installation docs

* Fix repositoryURL in sample seedJob configuration with SSH auth

* Slightly expand on #348

* Fix formatting in docs on Jenkins' customization, update plugin versions

* Add notes on Jenkins home Volume in Helm chart values.yaml and docs (#589)

* Auto-updated docs (#610)

Co-authored-by: Sig00rd <Sig00rd@users.noreply.github.com>

* Reimplemented the validation logic with caching the security warnings
- Reimplemented the validator interface
- Updated manifests to allocate more resources

* Add an issue template for documentation (#613)

* Docs: add info on restricted volumeMounts other than jenkins-home(#612)

* Update note in installation docs

* Update Helm chart default values.yaml

* Update schema

* Auto-updated docs (#616)

Co-authored-by: Sig00rd <Sig00rd@users.noreply.github.com>

* Auto-updated docs (#617)

Co-authored-by: Sig00rd <Sig00rd@users.noreply.github.com>

* Updated Validation logic
- Defined a security manager struct to cache all the plugin data
- Added flag to make validating security warnings optional while deploying the operator

* Helm Chart: Remove empty priorityClassName from Jenkins template (#618)

Also bump Helm Chart version to v0.5.2

* Added unit test cases for webhook

* Updated Helm Charts
- Optimized the charts
- Made the webhook optional
- Added cert manager as dependency to be installed while running webhook

* Updated unit tests, helm charts and validation logic

* Completed helm e2e tests and updated helm charts
- Completed helm tests for various scenarios
- Disabled startupapi check for cert manager webhook, defined a secret and updated templates
- Made the webhook completely optional

* Code optimization and cleanup

* Modified helm tests

* code cleanup and optimization
This commit is contained in:
sharmapulkit04
2021-08-30 08:21:52 +02:00
committed by Sylwia Brant
parent 4aa34157c3
commit 51f7ec8248
23 changed files with 19807 additions and 2909 deletions
+188 -14
View File
@@ -1,20 +1,26 @@
package helm
import (
"context"
"fmt"
"os/exec"
"time"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
"github.com/jenkinsci/kubernetes-operator/test/e2e"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:scaffold:imports
)
var _ = Describe("Jenkins controller", func() {
var _ = Describe("Jenkins Controller with webhook", func() {
var (
namespace *corev1.Namespace
)
@@ -23,12 +29,16 @@ var _ = Describe("Jenkins controller", func() {
namespace = e2e.CreateNamespace()
})
AfterEach(func() {
cmd := exec.Command("../../bin/helm", "delete", "jenkins", "--namespace", namespace.Name)
output, err := cmd.CombinedOutput()
Expect(err).NotTo(HaveOccurred(), string(output))
e2e.ShowLogsIfTestHasFailed(CurrentGinkgoTestDescription().Failed, namespace.Name)
e2e.DestroyNamespace(namespace)
})
Context("when deploying Helm Chart to cluster", func() {
It("creates Jenkins instance and configures it", func() {
Context("Deploys jenkins operator with helm charts with default values", func() {
It("Deploys Jenkins operator and configures default Jenkins instance", func() {
jenkins := &v1alpha2.Jenkins{
TypeMeta: v1alpha2.JenkinsTypeMeta(),
ObjectMeta: metav1.ObjectMeta{
@@ -39,22 +49,186 @@ var _ = Describe("Jenkins controller", func() {
cmd := exec.Command("../../bin/helm", "upgrade", "jenkins", "../../chart/jenkins-operator", "--namespace", namespace.Name, "--debug",
"--set-string", fmt.Sprintf("jenkins.namespace=%s", namespace.Name),
"--set-string", fmt.Sprintf("operator.image=%s", *imageName), "--install")
"--set-string", fmt.Sprintf("operator.image=%s", *imageName), "--install", "--wait")
output, err := cmd.CombinedOutput()
Expect(err).NotTo(HaveOccurred(), string(output))
e2e.WaitForJenkinsBaseConfigurationToComplete(jenkins)
e2e.WaitForJenkinsUserConfigurationToComplete(jenkins)
cmd = exec.Command("../../bin/helm", "upgrade", "jenkins", "../../chart/jenkins-operator", "--namespace", namespace.Name, "--debug",
"--set-string", fmt.Sprintf("jenkins.namespace=%s", namespace.Name),
"--set-string", fmt.Sprintf("operator.image=%s", *imageName), "--install")
output, err = cmd.CombinedOutput()
Expect(err).NotTo(HaveOccurred(), string(output))
e2e.WaitForJenkinsBaseConfigurationToComplete(jenkins)
e2e.WaitForJenkinsUserConfigurationToComplete(jenkins)
})
})
Context("Deploys jenkins operator with helm charts with validating webhook and jenkins instance disabled", func() {
It("Deploys operator,denies creating a jenkins cr and creates jenkins cr with validation turned off", func() {
By("Deploying the operator along with webhook and cert-manager")
cmd := exec.Command("../../bin/helm", "upgrade", "jenkins", "../../chart/jenkins-operator", "--namespace", namespace.Name, "--debug",
"--set-string", fmt.Sprintf("jenkins.namespace=%s", namespace.Name), "--set-string", fmt.Sprintf("operator.image=%s", *imageName),
"--set", fmt.Sprintf("webhook.enabled=%t", true), "--set", fmt.Sprintf("jenkins.enabled=%t", false), "--install", "--wait")
output, err := cmd.CombinedOutput()
Expect(err).NotTo(HaveOccurred(), string(output))
By("Waiting for the operator to fetch the plugin data ")
time.Sleep(time.Duration(200) * time.Second)
By("Denying a create request for a Jenkins custom resource with some plugins having security warnings and validation is turned on")
userplugins := []v1alpha2.Plugin{
{Name: "simple-theme-plugin", Version: "0.6"},
{Name: "audit-trail", Version: "3.5"},
{Name: "github", Version: "1.29.0"},
}
jenkins := CreateJenkinsCR("jenkins", namespace.Name, userplugins, true)
Expect(e2e.K8sClient.Create(context.TODO(), jenkins)).Should(MatchError("admission webhook \"vjenkins.kb.io\" denied the request: security vulnerabilities detected in the following user-defined plugins: \naudit-trail:3.5\ngithub:1.29.0"))
By("Creating the Jenkins resource with plugins not having any security warnings and validation is turned on")
userplugins = []v1alpha2.Plugin{
{Name: "simple-theme-plugin", Version: "0.6"},
{Name: "audit-trail", Version: "3.8"},
{Name: "github", Version: "1.31.0"},
}
jenkins = CreateJenkinsCR("jenkins", namespace.Name, userplugins, true)
Expect(e2e.K8sClient.Create(context.TODO(), jenkins)).Should(Succeed())
e2e.WaitForJenkinsBaseConfigurationToComplete(jenkins)
e2e.WaitForJenkinsUserConfigurationToComplete(jenkins)
})
It("Deploys operator, creates a jenkins cr and denies update request for another one", func() {
By("Deploying the operator along with webhook and cert-manager")
cmd := exec.Command("../../bin/helm", "upgrade", "jenkins", "../../chart/jenkins-operator", "--namespace", namespace.Name, "--debug",
"--set-string", fmt.Sprintf("jenkins.namespace=%s", namespace.Name), "--set-string", fmt.Sprintf("operator.image=%s", *imageName),
"--set", fmt.Sprintf("webhook.enabled=%t", true), "--set", fmt.Sprintf("jenkins.enabled=%t", false), "--install", "--wait")
output, err := cmd.CombinedOutput()
Expect(err).NotTo(HaveOccurred(), string(output))
By("Waiting for the operator to fetch the plugin data ")
time.Sleep(time.Duration(200) * time.Second)
By("Creating a Jenkins custom resource with some plugins having security warnings but validation is turned off")
userplugins := []v1alpha2.Plugin{
{Name: "simple-theme-plugin", Version: "0.6"},
{Name: "audit-trail", Version: "3.5"},
{Name: "github", Version: "1.29.0"},
}
jenkins := CreateJenkinsCR("jenkins", namespace.Name, userplugins, false)
Expect(e2e.K8sClient.Create(context.TODO(), jenkins)).Should(Succeed())
e2e.WaitForJenkinsBaseConfigurationToComplete(jenkins)
e2e.WaitForJenkinsUserConfigurationToComplete(jenkins)
By("Failing to update the Jenkins custom resource because some plugins have security warnings and validation is turned on")
userplugins = []v1alpha2.Plugin{
{Name: "vncviewer", Version: "1.7"},
{Name: "build-timestamp", Version: "1.0.3"},
{Name: "deployit-plugin", Version: "7.5.5"},
{Name: "github-branch-source", Version: "2.0.7"},
{Name: "aws-lambda-cloud", Version: "0.4"},
{Name: "groovy", Version: "1.31"},
{Name: "google-login", Version: "1.2"},
}
jenkins.Spec.Master.Plugins = userplugins
jenkins.Spec.ValidateSecurityWarnings = true
Expect(e2e.K8sClient.Update(context.TODO(), jenkins)).Should(MatchError("admission webhook \"vjenkins.kb.io\" denied the request: security vulnerabilities detected in the following user-defined plugins: \nvncviewer:1.7\ndeployit-plugin:7.5.5\ngithub-branch-source:2.0.7\ngroovy:1.31\ngoogle-login:1.2"))
})
})
})
func CreateJenkinsCR(name string, namespace string, userPlugins []v1alpha2.Plugin, validateSecurityWarnings bool) *v1alpha2.Jenkins {
jenkins := &v1alpha2.Jenkins{
TypeMeta: v1alpha2.JenkinsTypeMeta(),
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: v1alpha2.JenkinsSpec{
GroovyScripts: v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
Secret: v1alpha2.SecretRef{
Name: "",
},
},
},
ConfigurationAsCode: v1alpha2.ConfigurationAsCode{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
Secret: v1alpha2.SecretRef{
Name: "",
},
},
},
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Name: resources.JenkinsMasterContainerName,
Env: []corev1.EnvVar{
{
Name: "TEST_ENV",
Value: "test_env_value",
},
},
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/login",
Port: intstr.FromString("http"),
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: int32(100),
TimeoutSeconds: int32(4),
FailureThreshold: int32(40),
SuccessThreshold: int32(1),
PeriodSeconds: int32(10),
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/login",
Port: intstr.FromString("http"),
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: int32(80),
TimeoutSeconds: int32(4),
FailureThreshold: int32(30),
SuccessThreshold: int32(1),
PeriodSeconds: int32(5),
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "plugins-cache",
MountPath: "/usr/share/jenkins/ref/plugins",
},
},
},
{
Name: "envoyproxy",
Image: "envoyproxy/envoy-alpine:v1.14.1",
},
},
Plugins: userPlugins,
DisableCSRFProtection: false,
NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
Volumes: []corev1.Volume{
{
Name: "plugins-cache",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
},
},
ValidateSecurityWarnings: validateSecurityWarnings,
Service: v1alpha2.Service{
Type: corev1.ServiceTypeNodePort,
Port: constants.DefaultHTTPPortInt32,
},
JenkinsAPISettings: v1alpha2.JenkinsAPISettings{AuthorizationStrategy: v1alpha2.CreateUserAuthorizationStrategy},
},
}
return jenkins
}