From a26e9c69e7c528786f0dbcb34f483c06aeb23d1b Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Fri, 7 May 2021 11:49:44 +0530 Subject: [PATCH 1/9] changes for e2e validating webhook --- .github/workflows/gobuild.yml | 56 ++-- Makefile | 8 + go.mod | 1 + pkg/http-server/file-scan.go | 1 + pkg/http-server/health.go | 3 + pkg/http-server/remote-repo.go | 1 + pkg/http-server/webhook-scan-logs.go | 2 + pkg/http-server/webhook-scan.go | 1 + scripts/e2e-validating-webhook.sh | 9 + scripts/install-kind.sh | 7 + scripts/run-e2e.sh | 2 +- test/e2e/validatingwebhook/certgen.go | 95 +++++++ test/e2e/validatingwebhook/kubeclient.go | 127 ++++++++++ .../test-data/yamls/pod.yaml | 14 + .../test-data/yamls/webhook.yaml | 23 ++ .../validating_webhook_suite_test.go | 13 + .../validating_webhook_test.go | 239 ++++++++++++++++++ .../validatingwebhook_utils.go | 89 +++++++ 18 files changed, 665 insertions(+), 26 deletions(-) create mode 100755 scripts/e2e-validating-webhook.sh create mode 100755 scripts/install-kind.sh create mode 100644 test/e2e/validatingwebhook/certgen.go create mode 100644 test/e2e/validatingwebhook/kubeclient.go create mode 100644 test/e2e/validatingwebhook/test-data/yamls/pod.yaml create mode 100644 test/e2e/validatingwebhook/test-data/yamls/webhook.yaml create mode 100644 test/e2e/validatingwebhook/validating_webhook_suite_test.go create mode 100644 test/e2e/validatingwebhook/validating_webhook_test.go create mode 100644 test/e2e/validatingwebhook/validatingwebhook_utils.go diff --git a/.github/workflows/gobuild.yml b/.github/workflows/gobuild.yml index 86e8197fe..771a8b789 100644 --- a/.github/workflows/gobuild.yml +++ b/.github/workflows/gobuild.yml @@ -21,42 +21,48 @@ jobs: - name: Install golint run: go get -u golang.org/x/lint/golint - - name: Go validations - run: make validate + # - name: Go validations + # run: make validate - - name: Build Terrascan - run: make build + # - name: Build Terrascan + # run: make build - - name: Run unit tests - run: make unit-tests + # - name: Run unit tests + # run: make unit-tests - - name: Run e2e tests - run: make e2e-tests + # - name: Run e2e tests + # run: make e2e-tests + + - name: install kind + run: make install-kind + + - name: Run e2e validating webhook + run: make e2e-validating-webhook - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 # push image to Docker Hub - push: - # Ensure "validate" job passes before pushing image. - needs: validate + # push: + # # Ensure "validate" job passes before pushing image. + # needs: validate - runs-on: ubuntu-latest - if: github.event_name == 'push' + # runs-on: ubuntu-latest + # if: github.event_name == 'push' - steps: - - name: Checkout Terrascan - uses: actions/checkout@v1 + # steps: + # - name: Checkout Terrascan + # uses: actions/checkout@v1 - - name: Build Terrascan docker image - run: make docker-build + # - name: Build Terrascan docker image + # run: make docker-build - - name: Login to docker hub - run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u accurics --password-stdin + # - name: Login to docker hub + # run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u accurics --password-stdin - - name: Push Terrascan docker image - run: make docker-push + # - name: Push Terrascan docker image + # run: make docker-push - - name: Push Terrascan latest docker image - if: ${{ github.ref == 'refs/heads/master' }} - run: make docker-push-latest + # - name: Push Terrascan latest docker image + # if: ${{ github.ref == 'refs/heads/master' }} + # run: make docker-push-latest diff --git a/Makefile b/Makefile index ca7c7ac3c..9863b25a1 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,14 @@ unit-tests: e2e-tests: build ./scripts/run-e2e.sh +# run e2e validating webhook +e2e-validating-webhook: build + ./scripts/e2e-validating-webhook.sh + +# install kind +install-kind: + ./scripts/install-kind.sh + # build terrascan docker image docker-build: ./scripts/docker-build.sh diff --git a/go.mod b/go.mod index 4874f3313..6e4653702 100644 --- a/go.mod +++ b/go.mod @@ -42,5 +42,6 @@ require ( honnef.co/go/tools v0.1.3 // indirect k8s.io/api v0.19.2 k8s.io/apimachinery v0.19.2 + k8s.io/client-go v10.0.0+incompatible sigs.k8s.io/kustomize/api v0.8.5 ) diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go index 3ab6e36cc..d9a6a4f19 100644 --- a/pkg/http-server/file-scan.go +++ b/pkg/http-server/file-scan.go @@ -35,6 +35,7 @@ import ( // scanFile accepts uploaded file and runs scan on it func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: file scan request") // get url params params := mux.Vars(r) diff --git a/pkg/http-server/health.go b/pkg/http-server/health.go index ff5e54712..d9231d6fa 100644 --- a/pkg/http-server/health.go +++ b/pkg/http-server/health.go @@ -18,9 +18,12 @@ package httpserver import ( "net/http" + + "go.uber.org/zap" ) // Health returns the health of the http server func (g *APIHandler) Health(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: health check request") w.WriteHeader(http.StatusOK) } diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go index 06ca9c2ef..5734da2b9 100644 --- a/pkg/http-server/remote-repo.go +++ b/pkg/http-server/remote-repo.go @@ -50,6 +50,7 @@ type scanRemoteRepoReq struct { // scanRemoteRepo downloads the remote Iac repository and scans it for // violations func (g *APIHandler) scanRemoteRepo(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: remote repository scan request") // get url params params := mux.Vars(r) diff --git a/pkg/http-server/webhook-scan-logs.go b/pkg/http-server/webhook-scan-logs.go index d4733aefd..b631aded6 100644 --- a/pkg/http-server/webhook-scan-logs.go +++ b/pkg/http-server/webhook-scan-logs.go @@ -69,6 +69,7 @@ type webhookDisplayedShowLog struct { } func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: validating webhook' get logs request") if !config.GetK8sAdmissionControl().Dashboard { apiErrorResponse(w, ErrDashboardDisabled.Error(), http.StatusBadRequest) @@ -134,6 +135,7 @@ func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) { } func (g *APIHandler) getLogByUID(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: validating webhook's get log by uid request") if !config.GetK8sAdmissionControl().Dashboard { apiErrorResponse(w, ErrDashboardDisabled.Error(), http.StatusBadRequest) diff --git a/pkg/http-server/webhook-scan.go b/pkg/http-server/webhook-scan.go index ff88b7fc1..a3c55ea8d 100644 --- a/pkg/http-server/webhook-scan.go +++ b/pkg/http-server/webhook-scan.go @@ -31,6 +31,7 @@ import ( // validateK8SWebhook handles the incoming validating admission webhook from kubernetes API server func (g *APIHandler) validateK8SWebhook(w http.ResponseWriter, r *http.Request) { + zap.S().Info("handle: validating webhook request") var ( params = mux.Vars(r) diff --git a/scripts/e2e-validating-webhook.sh b/scripts/e2e-validating-webhook.sh new file mode 100755 index 000000000..09c734064 --- /dev/null +++ b/scripts/e2e-validating-webhook.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +export TERRASCAN_BIN_PATH=${PWD}/bin/terrascan + +go test -p 1 -v ./test/e2e/validatingwebhook/... \ No newline at end of file diff --git a/scripts/install-kind.sh b/scripts/install-kind.sh new file mode 100755 index 000000000..83647ea15 --- /dev/null +++ b/scripts/install-kind.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# install kind +sudo curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.10.0/kind-linux-amd64 +sudo chmod 755 ./kind +sudo mv ./kind /usr/local/bin +sudo chown -R $USER /usr/local/bin/kind \ No newline at end of file diff --git a/scripts/run-e2e.sh b/scripts/run-e2e.sh index fba71c5d1..9c76dd00c 100755 --- a/scripts/run-e2e.sh +++ b/scripts/run-e2e.sh @@ -6,4 +6,4 @@ set -o pipefail export TERRASCAN_BIN_PATH=${PWD}/bin/terrascan -go test -p 1 -v ./test/... \ No newline at end of file +go test `go list ./test/... | grep -v validating-webhook` -p 1 -v ./test/... \ No newline at end of file diff --git a/test/e2e/validatingwebhook/certgen.go b/test/e2e/validatingwebhook/certgen.go new file mode 100644 index 000000000..479248091 --- /dev/null +++ b/test/e2e/validatingwebhook/certgen.go @@ -0,0 +1,95 @@ +package validatingwebhook + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "math/big" + "net" + "os" + "time" +) + +// code in this file is borrowed from https://gist.github.com/samuel/8b500ddd3f6118d052b5e6bc16bc4c09, +// modified as per our need + +// GenerateCertificates generates tls certificate files with the path specified +func GenerateCertificates(certFilePath, privateKeyPath string) error { + // ip address of the machine would be required to be added as + // subject alternate name + ipAddr, err := getIP() + if err != nil { + return err + } + + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return err + } + + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Accurics"}, + Country: []string{"IN"}, + }, + IPAddresses: []net.IP{ipAddr}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 1), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return fmt.Errorf("failed to create certificate, err: %s", err.Error()) + } + + out := &bytes.Buffer{} + pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + certFile, err := os.Create(certFilePath) + if err != nil { + return err + } + defer certFile.Close() + certFile.Write(out.Bytes()) + + out.Reset() + + pem.Encode(out, pemBlockForKey(priv)) + privKeyFile, err := os.Create(privateKeyPath) + if err != nil { + return err + } + defer privKeyFile.Close() + privKeyFile.Write(out.Bytes()) + + return nil +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + default: + return nil + } +} + +// getIP finds preferred outbound ip of the machine +func getIP() (net.IP, error) { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + return nil, err + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP, nil +} diff --git a/test/e2e/validatingwebhook/kubeclient.go b/test/e2e/validatingwebhook/kubeclient.go new file mode 100644 index 000000000..d73b4acc7 --- /dev/null +++ b/test/e2e/validatingwebhook/kubeclient.go @@ -0,0 +1,127 @@ +package validatingwebhook + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "path/filepath" + + "github.com/mitchellh/go-homedir" + admissionv1 "k8s.io/api/admissionregistration/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +const ( + namespace = "default" +) + +type KubernetesClient struct { + client *kubernetes.Clientset +} + +func NewKubernetesClient() (*KubernetesClient, error) { + kubernetesClient := new(KubernetesClient) + var err error + kubernetesClient.client, err = kubernetesClient.getK8sClient() + if err != nil { + return nil, err + } + return kubernetesClient, nil +} + +// getK8sClient creates a kubernetes clientset with default config path +func (k *KubernetesClient) getK8sClient() (*kubernetes.Clientset, error) { + home, err := homedir.Dir() + if err != nil { + fmt.Println("home directory not found", err) + return nil, fmt.Errorf("home directory not found, error: %s", err.Error()) + } + + configPath := filepath.Join(home, ".kube", "config") + + config, err := clientcmd.BuildConfigFromFlags("", configPath) + if err != nil { + return nil, fmt.Errorf("failed to create k8s config, error: %s", err.Error()) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create K8s clientset, error: %s", err.Error()) + } + + return clientset, nil +} + +// CreateValidatingWebhookConfiguration creates a ValidatingWebhookConfiguration +func (k *KubernetesClient) CreateValidatingWebhookConfiguration(webhookFile, certFile, apiKey, port string) (*admissionv1.ValidatingWebhookConfiguration, error) { + webhooks := admissionv1.ValidatingWebhookConfiguration{} + data, err := ioutil.ReadFile(webhookFile) + if err != nil { + return nil, err + } + + reader := bytes.NewReader(data) + decoder := yaml.NewYAMLOrJSONDecoder(reader, 1024) + err = decoder.Decode(&webhooks) + if err != nil { + return nil, err + } + + certData, err := ioutil.ReadFile(certFile) + if err != nil { + return nil, err + } + + webhook := &webhooks.Webhooks[0] + webhook.ClientConfig.CABundle = certData + ip, err := getIP() + if err != nil { + return nil, err + } + + url := fmt.Sprintf("https://%s:%s/v1/k8s/webhooks/%s/scan/validate", ip.String(), port, apiKey) + webhook.ClientConfig.URL = &url + + admr := k.client.AdmissionregistrationV1() + + createdWebhookConfig, err := admr.ValidatingWebhookConfigurations().Create(context.TODO(), &webhooks, metav1.CreateOptions{}) + if err != nil { + fmt.Println(err) + return nil, err + } + return createdWebhookConfig, nil +} + +func (k *KubernetesClient) DeleteValidatingWebhookConfiguration(webhookConfigName string) error { + return k.client.AdmissionregistrationV1().ValidatingWebhookConfigurations().Delete(context.TODO(), webhookConfigName, metav1.DeleteOptions{}) +} + +func (k *KubernetesClient) CreatePod(resourceFile string) (*v1.Pod, error) { + pod := v1.Pod{} + data, err := ioutil.ReadFile(resourceFile) + if err != nil { + return nil, err + } + reader := bytes.NewReader(data) + decoder := yaml.NewYAMLOrJSONDecoder(reader, 1024) + err = decoder.Decode(&pod) + if err != nil { + return nil, err + } + + createdPod, err := k.client.CoreV1().Pods(namespace).Create(context.TODO(), &pod, metav1.CreateOptions{}) + if err != nil { + fmt.Println(err) + return nil, err + } + return createdPod, err +} + +func (k *KubernetesClient) DeletePod(podName string) error { + return k.client.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metav1.DeleteOptions{}) +} diff --git a/test/e2e/validatingwebhook/test-data/yamls/pod.yaml b/test/e2e/validatingwebhook/test-data/yamls/pod.yaml new file mode 100644 index 000000000..96acd2574 --- /dev/null +++ b/test/e2e/validatingwebhook/test-data/yamls/pod.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: myapp + labels: + name: myapp +spec: + containers: + - name: nginx-pod + image: nginx + resources: + limits: + memory: "128Mi" + cpu: "100m" \ No newline at end of file diff --git a/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml b/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml new file mode 100644 index 000000000..9daa02620 --- /dev/null +++ b/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml @@ -0,0 +1,23 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: localhost-validating-webhook +webhooks: + - name: localhost.terrascan.server + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - pods + - deployments + failurePolicy: Fail + clientConfig: + url: "" + caBundle: "" + sideEffects: None + admissionReviewVersions: ["v1"] diff --git a/test/e2e/validatingwebhook/validating_webhook_suite_test.go b/test/e2e/validatingwebhook/validating_webhook_suite_test.go new file mode 100644 index 000000000..82337e0fd --- /dev/null +++ b/test/e2e/validatingwebhook/validating_webhook_suite_test.go @@ -0,0 +1,13 @@ +package validatingwebhook_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestValidatingWebhook(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "ValidatingWebhook Suite") +} diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go new file mode 100644 index 000000000..e8ecd8c3d --- /dev/null +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -0,0 +1,239 @@ +package validatingwebhook_test + +import ( + "fmt" + "io" + "os" + "path/filepath" + "time" + + "github.com/accurics/terrascan/pkg/config" + "github.com/accurics/terrascan/pkg/utils" + "github.com/accurics/terrascan/test/e2e/validatingwebhook" + "github.com/accurics/terrascan/test/helper" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/onsi/gomega/gexec" + admissionv1 "k8s.io/api/admissionregistration/v1" +) + +const ( + certsFolder = "certs" + k8sWebhookApiKey = "K8S_WEBHOOK_API_KEY" + apiKeyValue = "accurics" + defaultTimeout = 10 +) + +var ( + kubeClient *validatingwebhook.KubernetesClient + terrascanBinaryPath string + certFileAbsPath string + privKeyFileAbsPath string + policyRootRelPath = filepath.Join("..", "test_data", "policies") +) + +var _ = Describe("ValidatingWebhook", func() { + + BeforeSuite(func() { + + // delete the default cluster if it is already running + err := validatingwebhook.DeleteDefaultKindCluster() + if err != nil { + message := fmt.Sprintf("error while deleting cluster. err: %v", err) + Fail(message) + } + + // create a new cluster + err = validatingwebhook.CreateDefaultKindCluster() + if err != nil { + message := fmt.Sprintf("error while creating cluster. err: %v", err) + Fail(message) + } + + // get k8s client + kubeClient, err = validatingwebhook.NewKubernetesClient() + if err != nil { + errMessage := fmt.Sprintf("failed to connected to default k8s cluster, error: %s", err.Error()) + Fail(errMessage) + } + + // get terrascan binary path + terrascanBinaryPath = helper.GetTerrascanBinaryPath() + + // create tls certificates for server + certFileAbsPath, privKeyFileAbsPath, err = validatingwebhook.CreateCertificate(certsFolder, "server.crt", "priv.key") + if err != nil { + errMessage := fmt.Sprintf("failed to create certificates, error: %s", err.Error()) + Fail(errMessage) + } + + // sleep added so that the default serviceaccount is get created + // this logic needs to be improved + time.Sleep(20 * time.Second) + }) + + AfterSuite(func() { + if utils.IsWindowsPlatform() { + gexec.Kill() + } else { + gexec.Terminate() + } + + // delete the cluster + err := validatingwebhook.DeleteDefaultKindCluster() + if err != nil { + message := fmt.Sprintf("error while deleting cluster. err: %v", err) + Fail(message) + } + + os.RemoveAll("certs") + }) + + Describe("terrascan server as validating webhook with various available config options", func() { + + When("validating webhook with default 'k8s-admission-control' config", func() { + + Context("by default validating webhook runs in blind mode", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + + It("should run server successfully", func() { + configFileName = "config1.toml" + // create a config file with default config values + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, nil) + Expect(err).NotTo(HaveOccurred()) + + os.Setenv(k8sWebhookApiKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /health")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/{iac}/{iacVersion}/{cloud}/local/file/scan")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/{iac}/{iacVersion}/{cloud}/remote/dir/scan")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /k8s/webhooks/{apiKey}/logs")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /k8s/webhooks/logs/{uid}")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/k8s/webhooks/{apiKey}/scan/validate")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9010")) + }) + + When("server is added as a validating webhook and resource is created", func() { + It("should get registered with k8s cluster as validating webhook", func() { + + webhookFilePath, err := filepath.Abs(filepath.Join("test-data", "yamls", "webhook.yaml")) + Expect(err).NotTo(HaveOccurred()) + + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, "9010") + Expect(err).NotTo(HaveOccurred()) + }) + + When("resource creation is requested, it should be handled by terrascan server", func() { + It("should be handled by terrascan server", func() { + // remove the config file + defer os.Remove(configFileName) + + podYamlAbsPath, err := filepath.Abs(filepath.Join("test-data", "yamls", "pod.yaml")) + Expect(err).NotTo(HaveOccurred()) + + pod, err := kubeClient.CreatePod(podYamlAbsPath) + Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) + Expect(err).NotTo(HaveOccurred()) + Expect(pod).NotTo(BeNil()) + + // delete pod + err = kubeClient.DeletePod(pod.GetName()) + Expect(err).NotTo(HaveOccurred()) + + // delete validating webhook configuration + err = kubeClient.DeleteValidatingWebhookConfiguration(webhookConfig.GetName()) + Expect(err).NotTo(HaveOccurred()) + + if utils.IsWindowsPlatform() { + session.Kill() + } else { + session.Terminate() + } + }) + }) + }) + }) + }) + + When("validating webhook config has 'dashboard' and 'save-requests' is enabled", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + var port string + + It("should run server successfully", func() { + port = "9011" + configFileName = "config2.toml" + + // create a config file with 'dashboard' set to true + terrascanConfig := config.TerrascanConfig{ + K8sAdmissionControl: config.K8sAdmissionControl{ + Dashboard: true, + SaveRequests: true, + }, + } + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + Expect(err).NotTo(HaveOccurred()) + + os.Setenv(k8sWebhookApiKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9011")) + }) + + When("server is added as a validating webhook and resource is created", func() { + It("should get registered with k8s cluster as validating webhook", func() { + + webhookFilePath, err := filepath.Abs(filepath.Join("test-data", "yamls", "webhook.yaml")) + Expect(err).NotTo(HaveOccurred()) + + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) + Expect(err).NotTo(HaveOccurred()) + }) + + When("resource creation is requested, it should be handled by terrascan server", func() { + It("should be handled by terrascan server", func() { + // remove the config file + defer os.Remove(configFileName) + + podYamlAbsPath, err := filepath.Abs(filepath.Join("test-data", "yamls", "pod.yaml")) + Expect(err).NotTo(HaveOccurred()) + + pod, err := kubeClient.CreatePod(podYamlAbsPath) + Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) + Expect(err).NotTo(HaveOccurred()) + Expect(pod).NotTo(BeNil()) + + // delete pod + err = kubeClient.DeletePod(pod.GetName()) + Expect(err).NotTo(HaveOccurred()) + + // delete validating webhook configuration + err = kubeClient.DeleteValidatingWebhookConfiguration(webhookConfig.GetName()) + Expect(err).NotTo(HaveOccurred()) + + if utils.IsWindowsPlatform() { + session.Kill() + } else { + session.Terminate() + } + }) + }) + }) + }) + + When("validating webhook config has 'denied-severity' specified", func() { + + }) + + When("validating webhook config has 'denied-categories' specified", func() { + + }) + }) +}) diff --git a/test/e2e/validatingwebhook/validatingwebhook_utils.go b/test/e2e/validatingwebhook/validatingwebhook_utils.go new file mode 100644 index 000000000..346e58708 --- /dev/null +++ b/test/e2e/validatingwebhook/validatingwebhook_utils.go @@ -0,0 +1,89 @@ +package validatingwebhook + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/accurics/terrascan/pkg/config" + "github.com/accurics/terrascan/pkg/utils" + "github.com/pelletier/go-toml" +) + +// CreateConfigFile creates a config file with test policy path +func CreateConfigFile(configFileName, policyRootRelPath string, terrascanConfig *config.TerrascanConfig) error { + policyAbsPath, err := filepath.Abs(policyRootRelPath) + if err != nil { + return err + } + + if utils.IsWindowsPlatform() { + policyAbsPath = strings.ReplaceAll(policyAbsPath, "\\", "\\\\") + } + + if terrascanConfig == nil { + terrascanConfig = &config.TerrascanConfig{} + } + + terrascanConfig.BasePath = policyAbsPath + terrascanConfig.RepoPath = policyAbsPath + + // create config file in work directory + file, err := os.Create(configFileName) + if err != nil { + return fmt.Errorf("config file creation failed, err: %v", err) + } + + contentBytes, err := toml.Marshal(terrascanConfig) + if err != nil { + return err + } + + _, err = file.WriteString(string(contentBytes)) + if err != nil { + return fmt.Errorf("error while writing to config file, err: %v", err) + } + return nil +} + +// CreateCertificate creates certificates required to run server in the folder specified +func CreateCertificate(certsFolder, certFileName, privKeyFileName string) (string, string, error) { + // create certs folder to keep certificates + os.Mkdir(certsFolder, 0755) + certFileAbsPath, err := filepath.Abs(filepath.Join(certsFolder, "server.crt")) + if err != nil { + return "", "", err + } + privKeyFileAbsPath, err := filepath.Abs(filepath.Join(certsFolder, "priv.key")) + if err != nil { + return "", "", err + } + err = GenerateCertificates(certFileAbsPath, privKeyFileAbsPath) + if err != nil { + return "", "", err + } + + return certFileAbsPath, privKeyFileAbsPath, nil +} + +// DeleteDefaultKindCluster deletes the default kind cluster +func DeleteDefaultKindCluster() error { + cmd := exec.Command("kind", "delete", "cluster") + err := cmd.Run() + if err != nil { + return err + } + return nil +} + +// CreateDefaultKindCluster creates the default kind cluster +func CreateDefaultKindCluster() error { + cmd := exec.Command("kind", "create", "cluster") + err := cmd.Run() + if err != nil { + return err + } + return nil +} From b5011cf15130e957702fdd1fd4a9f3aad0dd0485 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Wed, 12 May 2021 02:26:49 +0530 Subject: [PATCH 2/9] 1. added a new test policy for e2e vw 2. fix e2e tests after new policy addition --- .../kubernetes_ingress_human.txt | 2 +- .../kubernetes_ingress_human_verbose.txt | 2 +- .../kubernetes_ingress_json.txt | 2 +- .../kubernetes_ingress_junit_xml.txt | 4 +- .../kubernetes_ingress_xml.txt | 2 +- .../kubernetes_ingress_yaml.txt | 2 +- .../kubernetes_file_resource_skipping.txt | 2 +- .../terraform_file_resource_skipping.txt | 2 +- .../rules_filtering/skip_multiple_rules.txt | 2 +- .../rules_filtering/skip_single_rule.txt | 2 +- .../aws_ami_violation_human.txt | 2 +- .../aws_ami_violation_human_verbose.txt | 2 +- .../aws_ami_violation_json.txt | 2 +- .../aws_ami_violation_json_all.txt | 2 +- .../aws_ami_violation_json_recursive.txt | 2 +- .../aws_ami_violation_junit_xml.txt | 4 +- .../aws_ami_violation_xml.txt | 2 +- .../aws_ami_violation_yaml.txt | 2 +- .../aws_db_instance_json.txt | 2 +- .../aws_db_instance_json_show_passed.txt | 19 +- .../aws_db_instance_xml.txt | 2 +- .../aws_db_instance_yaml.txt | 2 +- .../scanned_with_no_aws_policies.txt | 2 +- test/e2e/server/server_file_scan_test.go | 4 +- test/e2e/server/server_remote_scan_test.go | 4 +- .../k8s/cve_2020_8554/AC-K8-NS-SE-M-0188.json | 15 ++ .../k8s/cve_2020_8554/ensurePrivateIP.rego | 15 ++ test/e2e/validatingwebhook/kubeclient.go | 25 ++ .../test-data/yamls/service.yaml | 17 ++ .../test-data/yamls/webhook.yaml | 2 +- .../validating_webhook_test.go | 222 +++++++++++++----- 31 files changed, 277 insertions(+), 94 deletions(-) create mode 100644 test/e2e/test_data/policies/k8s/cve_2020_8554/AC-K8-NS-SE-M-0188.json create mode 100644 test/e2e/test_data/policies/k8s/cve_2020_8554/ensurePrivateIP.rego create mode 100644 test/e2e/validatingwebhook/test-data/yamls/service.yaml diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human.txt index f7df239ea..ff76e63ba 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human.txt @@ -13,7 +13,7 @@ Scan Summary - File/Folder : /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/k8s/kubernetes_ingress_violation IaC Type : k8s Scanned At : 2021-03-02 15:51:59.060974 +0000 UTC - Policies Validated : 7 + Policies Validated : 8 Violated Policies : 1 Low : 0 Medium : 0 diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human_verbose.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human_verbose.txt index 5054789d6..894905481 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human_verbose.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_human_verbose.txt @@ -18,7 +18,7 @@ Scan Summary - File/Folder : /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/k8s/kubernetes_ingress_violation IaC Type : k8s Scanned At : 2021-03-02 15:52:18.820415 +0000 UTC - Policies Validated : 7 + Policies Validated : 8 Violated Policies : 1 Low : 0 Medium : 0 diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_json.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_json.txt index 3ed713e39..913068367 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_json.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_json.txt @@ -18,7 +18,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/k8s/kubernetes_ingress_violation", "iac_type": "k8s", "scanned_at": "2021-03-02 15:52:42.748543 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 1, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_junit_xml.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_junit_xml.txt index 98f68ac20..6b49d4a4b 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_junit_xml.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_junit_xml.txt @@ -1,5 +1,5 @@ - - + + diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_xml.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_xml.txt index 78d5100f6..f7faaf259 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_xml.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_xml.txt @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_yaml.txt b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_yaml.txt index b459d61c9..99612a4d6 100644 --- a/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_yaml.txt +++ b/test/e2e/scan/golden/k8s_scans/k8s/kubernetes_ingress_violations/kubernetes_ingress_yaml.txt @@ -14,7 +14,7 @@ results: file/folder: /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/k8s/kubernetes_ingress_violation iac_type: k8s scanned_at: 2021-03-02 15:53:30.996294 +0000 UTC - policies_validated: 7 + policies_validated: 8 violated_policies: 1 low: 0 medium: 0 diff --git a/test/e2e/scan/golden/resource_skipping/kubernetes_file_resource_skipping.txt b/test/e2e/scan/golden/resource_skipping/kubernetes_file_resource_skipping.txt index 900816327..543a4c947 100644 --- a/test/e2e/scan/golden/resource_skipping/kubernetes_file_resource_skipping.txt +++ b/test/e2e/scan/golden/resource_skipping/kubernetes_file_resource_skipping.txt @@ -6,7 +6,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/resource_skipping/kubernetes", "iac_type": "k8s", "scanned_at": "2021-03-02 16:01:16.973652 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 0, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/resource_skipping/terraform_file_resource_skipping.txt b/test/e2e/scan/golden/resource_skipping/terraform_file_resource_skipping.txt index 8da85deb7..91de041ad 100644 --- a/test/e2e/scan/golden/resource_skipping/terraform_file_resource_skipping.txt +++ b/test/e2e/scan/golden/resource_skipping/terraform_file_resource_skipping.txt @@ -179,7 +179,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/resource_skipping/terraform", "iac_type": "terraform", "scanned_at": "2021-03-02 16:00:46.95002 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 11, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/rules_filtering/skip_multiple_rules.txt b/test/e2e/scan/golden/rules_filtering/skip_multiple_rules.txt index 742441bb1..dac8de89c 100644 --- a/test/e2e/scan/golden/rules_filtering/skip_multiple_rules.txt +++ b/test/e2e/scan/golden/rules_filtering/skip_multiple_rules.txt @@ -19,7 +19,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_db_instance_violation", "iac_type": "terraform", "scanned_at": "2021-03-02 15:59:24.626711 +0000 UTC", - "policies_validated": 4, + "policies_validated": 5, "violated_policies": 1, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/rules_filtering/skip_single_rule.txt b/test/e2e/scan/golden/rules_filtering/skip_single_rule.txt index b053f71e4..e36bd8519 100644 --- a/test/e2e/scan/golden/rules_filtering/skip_single_rule.txt +++ b/test/e2e/scan/golden/rules_filtering/skip_single_rule.txt @@ -103,7 +103,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_db_instance_violation", "iac_type": "terraform", "scanned_at": "2021-03-02 13:53:14.255721 +0000 UTC", - "policies_validated": 6, + "policies_validated": 7, "violated_policies": 8, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human.txt index bfe0192da..c674012f9 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human.txt @@ -14,7 +14,7 @@ Scan Summary - File/Folder : /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation IaC Type : terraform Scanned At : 2021-03-02 15:45:17.636568 +0000 UTC - Policies Validated : 7 + Policies Validated : 8 Violated Policies : 1 Low : 0 Medium : 1 diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human_verbose.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human_verbose.txt index c1313c44a..6487faf04 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human_verbose.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_human_verbose.txt @@ -19,7 +19,7 @@ Scan Summary - File/Folder : /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation IaC Type : terraform Scanned At : 2021-03-02 15:45:36.980596 +0000 UTC - Policies Validated : 7 + Policies Validated : 8 Violated Policies : 1 Low : 0 Medium : 1 diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json.txt index 529907af8..cc9e93c94 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json.txt @@ -19,7 +19,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation", "iac_type": "terraform", "scanned_at": "2021-03-02 15:45:55.603722 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 1, "low": 0, "medium": 1, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_all.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_all.txt index 9713e8c4b..fb84ea819 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_all.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_all.txt @@ -31,7 +31,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation", "iac_type": "all", "scanned_at": "2021-03-02 15:45:55.603722 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 1, "low": 0, "medium": 1, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_recursive.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_recursive.txt index 54b01bd40..7c5fdf434 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_recursive.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_json_recursive.txt @@ -31,7 +31,7 @@ "file/folder": "/Users/pankajpatil/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/terraform_recursive", "iac_type": "terraform", "scanned_at": "2021-04-18 12:45:51.597994 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 1, "low": 0, "medium": 1, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_junit_xml.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_junit_xml.txt index 28153188b..3f61daea1 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_junit_xml.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_junit_xml.txt @@ -1,5 +1,5 @@ - - + + diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_xml.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_xml.txt index ee7626527..1328be501 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_xml.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_xml.txt @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_yaml.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_yaml.txt index afaa372d3..f4ee1b044 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_yaml.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_ami_violations/aws_ami_violation_yaml.txt @@ -15,7 +15,7 @@ results: file/folder: /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation iac_type: terraform scanned_at: 2021-03-02 15:46:38.259501 +0000 UTC - policies_validated: 7 + policies_validated: 8 violated_policies: 1 low: 0 medium: 1 diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json.txt index 2c6534c0b..77a862c8b 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json.txt @@ -175,7 +175,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_db_instance_violation", "iac_type": "terraform", "scanned_at": "2021-03-02 15:48:06.923537 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 14, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json_show_passed.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json_show_passed.txt index 92ade3e97..cfb10a173 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json_show_passed.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_json_show_passed.txt @@ -2,11 +2,11 @@ "results": { "passed_rules": [ { - "rule_name": "rdsCAExpired", - "description": "Ensure Certificate used in RDS instance is updated", - "rule_id": "AWS.RDS.DS.High.1042", - "severity": "HIGH", - "category": "Data Security" + "rule_name": "ensurePrivateIP", + "description": "Vulnerable to CVE-2020-8554", + "rule_id": "AC-K8-NS-SE-M-0188", + "severity": "MEDIUM", + "category": "Network Security" }, { "rule_name": "noHttps", @@ -21,6 +21,13 @@ "rule_id": "AWS.EC2.Encryption\u0026KeyManagement.Medium.0688", "severity": "MEDIUM", "category": "Encryption \u0026 KeyManagement" + }, + { + "rule_name": "rdsCAExpired", + "description": "Ensure Certificate used in RDS instance is updated", + "rule_id": "AWS.RDS.DS.High.1042", + "severity": "HIGH", + "category": "Data Security" } ], "violations": [ @@ -198,7 +205,7 @@ "file/folder": "/Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_db_instance_violation", "iac_type": "terraform", "scanned_at": "2021-03-03 07:01:04.624061 +0000 UTC", - "policies_validated": 7, + "policies_validated": 8, "violated_policies": 14, "low": 0, "medium": 0, diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_xml.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_xml.txt index 244324cde..b5aa442b8 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_xml.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_xml.txt @@ -18,5 +18,5 @@ - + \ No newline at end of file diff --git a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_yaml.txt b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_yaml.txt index 3ec76b582..70726979e 100644 --- a/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_yaml.txt +++ b/test/e2e/scan/golden/terraform_scans/aws/aws_db_instance_violations/aws_db_instance_yaml.txt @@ -145,7 +145,7 @@ results: file/folder: /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_db_instance_violation iac_type: terraform scanned_at: 2021-03-02 15:48:25.531792 +0000 UTC - policies_validated: 7 + policies_validated: 8 violated_policies: 14 low: 0 medium: 0 diff --git a/test/e2e/scan/golden/terraform_scans/scanned_with_no_aws_policies.txt b/test/e2e/scan/golden/terraform_scans/scanned_with_no_aws_policies.txt index 0372f74b8..2337d152b 100644 --- a/test/e2e/scan/golden/terraform_scans/scanned_with_no_aws_policies.txt +++ b/test/e2e/scan/golden/terraform_scans/scanned_with_no_aws_policies.txt @@ -3,7 +3,7 @@ Scan Summary - File/Folder : /Users/apple/go/src/github.com/patilpankaj212/terrascan/test/e2e/test_data/iac/aws/aws_ami_violation IaC Type : terraform Scanned At : 2021-03-02 15:50:51.746328 +0000 UTC - Policies Validated : 1 + Policies Validated : 2 Violated Policies : 0 Low : 0 Medium : 0 diff --git a/test/e2e/server/server_file_scan_test.go b/test/e2e/server/server_file_scan_test.go index 17089ec77..d60905aeb 100644 --- a/test/e2e/server/server_file_scan_test.go +++ b/test/e2e/server/server_file_scan_test.go @@ -225,8 +225,8 @@ var _ = Describe("Server File Scan", func() { err := json.Unmarshal(responseBytes, &responseEngineOutput) Expect(err).NotTo(HaveOccurred()) - // There are total 7 rules in the test policies directory, out of which 1 is skipped - Expect(responseEngineOutput.ViolationStore.Summary.TotalPolicies).To(BeIdenticalTo(6)) + // There are total 8 rules in the test policies directory, out of which 1 is skipped + Expect(responseEngineOutput.ViolationStore.Summary.TotalPolicies).To(BeIdenticalTo(7)) }) }) diff --git a/test/e2e/server/server_remote_scan_test.go b/test/e2e/server/server_remote_scan_test.go index 6c4eac844..6ef13b5d0 100644 --- a/test/e2e/server/server_remote_scan_test.go +++ b/test/e2e/server/server_remote_scan_test.go @@ -416,8 +416,8 @@ var _ = Describe("Server Remote Scan", func() { err := json.Unmarshal(responseBytes, &responseEngineOutput) Expect(err).NotTo(HaveOccurred()) - // There are total 7 rules in the test policies directory, out of which 1 is skipped - Expect(responseEngineOutput.ViolationStore.Summary.TotalPolicies).To(BeIdenticalTo(6)) + // There are total 8 rules in the test policies directory, out of which 1 is skipped + Expect(responseEngineOutput.ViolationStore.Summary.TotalPolicies).To(BeIdenticalTo(7)) }) }) diff --git a/test/e2e/test_data/policies/k8s/cve_2020_8554/AC-K8-NS-SE-M-0188.json b/test/e2e/test_data/policies/k8s/cve_2020_8554/AC-K8-NS-SE-M-0188.json new file mode 100644 index 000000000..70157bc7e --- /dev/null +++ b/test/e2e/test_data/policies/k8s/cve_2020_8554/AC-K8-NS-SE-M-0188.json @@ -0,0 +1,15 @@ +{ + "name": "ensurePrivateIP", + "file": "ensurePrivateIP.rego", + "template_args": { + "name": "ensurePrivateIP", + "prefix": "", + "resource_type": "kubernetes_service", + "suffix": "" + }, + "severity": "MEDIUM", + "description": "Vulnerable to CVE-2020-8554", + "reference_id": "AC-K8-NS-SE-M-0188", + "category": "Network Security", + "version": 1 +} \ No newline at end of file diff --git a/test/e2e/test_data/policies/k8s/cve_2020_8554/ensurePrivateIP.rego b/test/e2e/test_data/policies/k8s/cve_2020_8554/ensurePrivateIP.rego new file mode 100644 index 000000000..e195b2885 --- /dev/null +++ b/test/e2e/test_data/policies/k8s/cve_2020_8554/ensurePrivateIP.rego @@ -0,0 +1,15 @@ +package accurics + +{{.prefix}}{{.name}}{{.suffix}}[service.id] { + service := input.{{.resource_type}}[_] + type_check(service.config.spec) + object.get(service.config.spec, "externalIPs", "undefined") != "undefined" +} + +type_check(spec) { + spec.type == "ClusterIP" +} + +type_check(spec) { + object.get(spec, "type", "undefined") == "undefined" +} \ No newline at end of file diff --git a/test/e2e/validatingwebhook/kubeclient.go b/test/e2e/validatingwebhook/kubeclient.go index d73b4acc7..15fbf1475 100644 --- a/test/e2e/validatingwebhook/kubeclient.go +++ b/test/e2e/validatingwebhook/kubeclient.go @@ -125,3 +125,28 @@ func (k *KubernetesClient) CreatePod(resourceFile string) (*v1.Pod, error) { func (k *KubernetesClient) DeletePod(podName string) error { return k.client.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metav1.DeleteOptions{}) } + +func (k *KubernetesClient) CreateService(resourceFile string) (*v1.Service, error) { + service := v1.Service{} + data, err := ioutil.ReadFile(resourceFile) + if err != nil { + return nil, err + } + reader := bytes.NewReader(data) + decoder := yaml.NewYAMLOrJSONDecoder(reader, 1024) + err = decoder.Decode(&service) + if err != nil { + return nil, err + } + + createdService, err := k.client.CoreV1().Services(namespace).Create(context.TODO(), &service, metav1.CreateOptions{}) + if err != nil { + fmt.Println(err) + return nil, err + } + return createdService, err +} + +func (k *KubernetesClient) DeleteService(serviceName string) error { + return k.client.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{}) +} diff --git a/test/e2e/validatingwebhook/test-data/yamls/service.yaml b/test/e2e/validatingwebhook/test-data/yamls/service.yaml new file mode 100644 index 000000000..a19b41479 --- /dev/null +++ b/test/e2e/validatingwebhook/test-data/yamls/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: allowed-external-ip +spec: + type: ClusterIP + selector: + app: MyApp + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 8080 + externalIPs: + - 192.168.10.10 + - 8.8.8.8 + - 203.0.113.0 \ No newline at end of file diff --git a/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml b/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml index 9daa02620..a91f59b30 100644 --- a/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml +++ b/test/e2e/validatingwebhook/test-data/yamls/webhook.yaml @@ -14,7 +14,7 @@ webhooks: - UPDATE resources: - pods - - deployments + - services failurePolicy: Fail clientConfig: url: "" diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index e8ecd8c3d..b165cb902 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -16,6 +16,7 @@ import ( "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" admissionv1 "k8s.io/api/admissionregistration/v1" + k8serr "k8s.io/apimachinery/pkg/api/errors" ) const ( @@ -31,6 +32,9 @@ var ( certFileAbsPath string privKeyFileAbsPath string policyRootRelPath = filepath.Join("..", "test_data", "policies") + webhookYamlRelPath = filepath.Join("test-data", "yamls", "webhook.yaml") + podYamlRelPath = filepath.Join("test-data", "yamls", "pod.yaml") + serviceYamlPath = filepath.Join("test-data", "yamls", "service.yaml") ) var _ = Describe("ValidatingWebhook", func() { @@ -87,7 +91,7 @@ var _ = Describe("ValidatingWebhook", func() { Fail(message) } - os.RemoveAll("certs") + os.RemoveAll(certsFolder) }) Describe("terrascan server as validating webhook with various available config options", func() { @@ -100,7 +104,7 @@ var _ = Describe("ValidatingWebhook", func() { var webhookConfig *admissionv1.ValidatingWebhookConfiguration var configFileName string - It("should run server successfully", func() { + It("server should start running on port 9010", func() { configFileName = "config1.toml" // create a config file with default config values err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, nil) @@ -109,51 +113,25 @@ var _ = Describe("ValidatingWebhook", func() { os.Setenv(k8sWebhookApiKey, apiKeyValue) args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /health")) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/{iac}/{iacVersion}/{cloud}/local/file/scan")) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/{iac}/{iacVersion}/{cloud}/remote/dir/scan")) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /k8s/webhooks/{apiKey}/logs")) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route GET - /k8s/webhooks/logs/{uid}")) - Eventually(session.Err, defaultTimeout).Should(gbytes.Say("Route POST - /v1/k8s/webhooks/{apiKey}/scan/validate")) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9010")) }) - When("server is added as a validating webhook and resource is created", func() { - It("should get registered with k8s cluster as validating webhook", func() { + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { - webhookFilePath, err := filepath.Abs(filepath.Join("test-data", "yamls", "webhook.yaml")) + webhookFilePath, err := filepath.Abs(webhookYamlRelPath) Expect(err).NotTo(HaveOccurred()) webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, "9010") Expect(err).NotTo(HaveOccurred()) }) - When("resource creation is requested, it should be handled by terrascan server", func() { - It("should be handled by terrascan server", func() { + When("pod creation addmission requested is sent to server", func() { + It("server should get the addmission request to review", func() { // remove the config file defer os.Remove(configFileName) - podYamlAbsPath, err := filepath.Abs(filepath.Join("test-data", "yamls", "pod.yaml")) - Expect(err).NotTo(HaveOccurred()) - - pod, err := kubeClient.CreatePod(podYamlAbsPath) - Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) - Expect(err).NotTo(HaveOccurred()) - Expect(pod).NotTo(BeNil()) - - // delete pod - err = kubeClient.DeletePod(pod.GetName()) - Expect(err).NotTo(HaveOccurred()) - - // delete validating webhook configuration - err = kubeClient.DeleteValidatingWebhookConfiguration(webhookConfig.GetName()) - Expect(err).NotTo(HaveOccurred()) - - if utils.IsWindowsPlatform() { - session.Kill() - } else { - session.Terminate() - } + createPod(session, webhookConfig.GetName()) }) }) }) @@ -167,7 +145,7 @@ var _ = Describe("ValidatingWebhook", func() { var configFileName string var port string - It("should run server successfully", func() { + It("server should start running on port 9011", func() { port = "9011" configFileName = "config2.toml" @@ -187,53 +165,179 @@ var _ = Describe("ValidatingWebhook", func() { Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9011")) }) - When("server is added as a validating webhook and resource is created", func() { - It("should get registered with k8s cluster as validating webhook", func() { + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { - webhookFilePath, err := filepath.Abs(filepath.Join("test-data", "yamls", "webhook.yaml")) + webhookFileAbsPath, err := filepath.Abs(filepath.Join(webhookYamlRelPath)) Expect(err).NotTo(HaveOccurred()) - webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFileAbsPath, certFileAbsPath, apiKeyValue, port) Expect(err).NotTo(HaveOccurred()) }) - When("resource creation is requested, it should be handled by terrascan server", func() { - It("should be handled by terrascan server", func() { + When("pod creation addmission requested is sent to server", func() { + It("server should get the addmission request to review", func() { // remove the config file defer os.Remove(configFileName) - podYamlAbsPath, err := filepath.Abs(filepath.Join("test-data", "yamls", "pod.yaml")) - Expect(err).NotTo(HaveOccurred()) + createPod(session, webhookConfig.GetName()) + }) + }) + }) + }) - pod, err := kubeClient.CreatePod(podYamlAbsPath) - Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) - Expect(err).NotTo(HaveOccurred()) - Expect(pod).NotTo(BeNil()) + When("validating webhook config has 'denied-severity' specified", func() { + + Context("service to be created violates a policy which has 'MEDIUM' seveirty", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + var port string + + It("server should start running on port 9012", func() { + port = "9012" + configFileName = "config3.toml" + + // create a config file with desired severity specified + terrascanConfig := config.TerrascanConfig{ + K8sAdmissionControl: config.K8sAdmissionControl{ + DeniedSeverity: "MEDIUM", + }, + } + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + Expect(err).NotTo(HaveOccurred()) - // delete pod - err = kubeClient.DeletePod(pod.GetName()) + os.Setenv(k8sWebhookApiKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9012")) + }) + + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { + + webhookFilePath, err := filepath.Abs(filepath.Join(webhookYamlRelPath)) Expect(err).NotTo(HaveOccurred()) - // delete validating webhook configuration - err = kubeClient.DeleteValidatingWebhookConfiguration(webhookConfig.GetName()) + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) Expect(err).NotTo(HaveOccurred()) + }) + + When("service creation addmission requested is sent to server", func() { + It("server should get the addmission request to review and reject the request", func() { + // remove the config file + defer os.Remove(configFileName) - if utils.IsWindowsPlatform() { - session.Kill() - } else { - session.Terminate() - } + createService(session, webhookConfig.GetName()) + }) }) }) }) }) - When("validating webhook config has 'denied-severity' specified", func() { + When("validating webhook config has 'denied-categories' specified", func() { + Context("service to be created violates a policy which has 'Network Security' category", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + var port string + + It("server should start running on port 9013", func() { + port = "9013" + configFileName = "config4.toml" + + // create a config file with desired severity specified + terrascanConfig := config.TerrascanConfig{ + K8sAdmissionControl: config.K8sAdmissionControl{ + Categories: []string{"Network Security"}, + }, + } + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + Expect(err).NotTo(HaveOccurred()) - }) + os.Setenv(k8sWebhookApiKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9013")) + }) - When("validating webhook config has 'denied-categories' specified", func() { + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { + webhookFilePath, err := filepath.Abs(filepath.Join(webhookYamlRelPath)) + Expect(err).NotTo(HaveOccurred()) + + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) + Expect(err).NotTo(HaveOccurred()) + }) + + When("service creation addmission requested is sent to server", func() { + It("server should get the addmission request to review and reject the request", func() { + // remove the config file + defer os.Remove(configFileName) + + createService(session, webhookConfig.GetName()) + }) + }) + }) + }) }) }) }) + +// createService creates a service and asserts for reject status, +// and deletes the resources +func createService(session *gexec.Session, webhookName string) { + serviceYamlAbsPath, err := filepath.Abs(filepath.Join(serviceYamlPath)) + Expect(err).NotTo(HaveOccurred()) + + service, err := kubeClient.CreateService(serviceYamlAbsPath) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("handle: validating webhook request")) + Expect(err).To(HaveOccurred()) + + if e, ok := err.(*k8serr.StatusError); ok { + Expect(e.Status().Code).To(BeNumerically("==", 403)) + } else { + errMessage := fmt.Sprintf("expected error to be of type 'k8s.io/apimachinery/pkg/api/errors.StatusError', got of type %T", err) + Fail(errMessage) + } + Expect(service).To(BeNil()) + + // delete validating webhook configuration + err = kubeClient.DeleteValidatingWebhookConfiguration(webhookName) + Expect(err).NotTo(HaveOccurred()) + + if utils.IsWindowsPlatform() { + session.Kill() + } else { + session.Terminate() + } +} + +// createPod creates a pod and asserts for reject status, +// and deletes the resources +func createPod(session *gexec.Session, webhookName string) { + podYamlAbsPath, err := filepath.Abs(filepath.Join(podYamlRelPath)) + Expect(err).NotTo(HaveOccurred()) + + pod, err := kubeClient.CreatePod(podYamlAbsPath) + Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) + Expect(err).NotTo(HaveOccurred()) + Expect(pod).NotTo(BeNil()) + + // delete pod + err = kubeClient.DeletePod(pod.GetName()) + Expect(err).NotTo(HaveOccurred()) + + // delete validating webhook configuration + err = kubeClient.DeleteValidatingWebhookConfiguration(webhookName) + Expect(err).NotTo(HaveOccurred()) + + if utils.IsWindowsPlatform() { + session.Kill() + } else { + session.Terminate() + } +} From 51cf77162b2cde1c2f02e9fe0fd61fd6d9a8d115 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Wed, 12 May 2021 02:36:33 +0530 Subject: [PATCH 3/9] 1. go mod tidy 2. build file changes 3. add copyright --- .github/workflows/gobuild.yml | 53 +++++++++---------- go.mod | 6 +-- go.sum | 20 ++++--- scripts/run-e2e.sh | 2 +- test/e2e/validatingwebhook/certgen.go | 16 ++++++ test/e2e/validatingwebhook/kubeclient.go | 24 +++++++++ .../validating_webhook_suite_test.go | 16 ++++++ .../validating_webhook_test.go | 26 +++++++-- .../validatingwebhook_utils.go | 16 ++++++ 9 files changed, 136 insertions(+), 43 deletions(-) diff --git a/.github/workflows/gobuild.yml b/.github/workflows/gobuild.yml index 771a8b789..898440dde 100644 --- a/.github/workflows/gobuild.yml +++ b/.github/workflows/gobuild.yml @@ -21,48 +21,45 @@ jobs: - name: Install golint run: go get -u golang.org/x/lint/golint - # - name: Go validations - # run: make validate + - name: Go validations + run: make validate - # - name: Build Terrascan - # run: make build + - name: Build Terrascan + run: make build - # - name: Run unit tests - # run: make unit-tests - - # - name: Run e2e tests - # run: make e2e-tests + - name: Run unit tests + run: make unit-tests - name: install kind run: make install-kind - - name: Run e2e validating webhook - run: make e2e-validating-webhook + - name: Run e2e tests + run: make e2e-tests - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 # push image to Docker Hub - # push: - # # Ensure "validate" job passes before pushing image. - # needs: validate + push: + # Ensure "validate" job passes before pushing image. + needs: validate - # runs-on: ubuntu-latest - # if: github.event_name == 'push' + runs-on: ubuntu-latest + if: github.event_name == 'push' - # steps: - # - name: Checkout Terrascan - # uses: actions/checkout@v1 + steps: + - name: Checkout Terrascan + uses: actions/checkout@v1 - # - name: Build Terrascan docker image - # run: make docker-build + - name: Build Terrascan docker image + run: make docker-build - # - name: Login to docker hub - # run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u accurics --password-stdin + - name: Login to docker hub + run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u accurics --password-stdin - # - name: Push Terrascan docker image - # run: make docker-push + - name: Push Terrascan docker image + run: make docker-push - # - name: Push Terrascan latest docker image - # if: ${{ github.ref == 'refs/heads/master' }} - # run: make docker-push-latest + - name: Push Terrascan latest docker image + if: ${{ github.ref == 'refs/heads/master' }} + run: make docker-push-latest diff --git a/go.mod b/go.mod index 6e4653702..21e6e98b4 100644 --- a/go.mod +++ b/go.mod @@ -34,12 +34,12 @@ require ( github.com/spf13/cobra v1.1.1 github.com/zclconf/go-cty v1.7.1 go.uber.org/zap v1.16.0 - golang.org/x/mod v0.4.2 // indirect - golang.org/x/sys v0.0.0-20210415045647-66c3f260301c + golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 + golang.org/x/tools v0.1.1 // indirect gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b helm.sh/helm/v3 v3.4.0 - honnef.co/go/tools v0.1.3 // indirect + honnef.co/go/tools v0.1.4 // indirect k8s.io/api v0.19.2 k8s.io/apimachinery v0.19.2 k8s.io/client-go v10.0.0+incompatible diff --git a/go.sum b/go.sum index 1875706aa..d1a44be32 100644 --- a/go.sum +++ b/go.sum @@ -919,6 +919,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1065,8 +1066,9 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1083,6 +1085,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1141,10 +1144,14 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210415045647-66c3f260301c h1:6L+uOeS3OQt/f4eFHXZcTxeZrGCuz+CLElgEBjbcTA4= -golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1216,8 +1223,9 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201028111035-eafbe7b904eb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1374,8 +1382,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +honnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ= +honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= k8s.io/apiextensions-apiserver v0.19.2 h1:oG84UwiDsVDu7dlsGQs5GySmQHCzMhknfhFExJMz9tA= diff --git a/scripts/run-e2e.sh b/scripts/run-e2e.sh index 9c76dd00c..fba71c5d1 100755 --- a/scripts/run-e2e.sh +++ b/scripts/run-e2e.sh @@ -6,4 +6,4 @@ set -o pipefail export TERRASCAN_BIN_PATH=${PWD}/bin/terrascan -go test `go list ./test/... | grep -v validating-webhook` -p 1 -v ./test/... \ No newline at end of file +go test -p 1 -v ./test/... \ No newline at end of file diff --git a/test/e2e/validatingwebhook/certgen.go b/test/e2e/validatingwebhook/certgen.go index 479248091..50b2de4e3 100644 --- a/test/e2e/validatingwebhook/certgen.go +++ b/test/e2e/validatingwebhook/certgen.go @@ -1,3 +1,19 @@ +/* + Copyright (C) 2020 Accurics, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package validatingwebhook import ( diff --git a/test/e2e/validatingwebhook/kubeclient.go b/test/e2e/validatingwebhook/kubeclient.go index 15fbf1475..b662af494 100644 --- a/test/e2e/validatingwebhook/kubeclient.go +++ b/test/e2e/validatingwebhook/kubeclient.go @@ -1,3 +1,19 @@ +/* + Copyright (C) 2020 Accurics, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package validatingwebhook import ( @@ -20,10 +36,13 @@ const ( namespace = "default" ) +// KubernetesClient will connect to local k8s cluster, +// and help perform resource operation type KubernetesClient struct { client *kubernetes.Clientset } +// NewKubernetesClient creates a new Kubernetes client func NewKubernetesClient() (*KubernetesClient, error) { kubernetesClient := new(KubernetesClient) var err error @@ -97,10 +116,12 @@ func (k *KubernetesClient) CreateValidatingWebhookConfiguration(webhookFile, cer return createdWebhookConfig, nil } +// DeleteValidatingWebhookConfiguration will delete the specified webhook name func (k *KubernetesClient) DeleteValidatingWebhookConfiguration(webhookConfigName string) error { return k.client.AdmissionregistrationV1().ValidatingWebhookConfigurations().Delete(context.TODO(), webhookConfigName, metav1.DeleteOptions{}) } +// CreatePod will create a pod by parsing a resource file func (k *KubernetesClient) CreatePod(resourceFile string) (*v1.Pod, error) { pod := v1.Pod{} data, err := ioutil.ReadFile(resourceFile) @@ -122,10 +143,12 @@ func (k *KubernetesClient) CreatePod(resourceFile string) (*v1.Pod, error) { return createdPod, err } +// DeletePod will delete the specified pod name func (k *KubernetesClient) DeletePod(podName string) error { return k.client.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metav1.DeleteOptions{}) } +// CreateService will a service by parsing a resource file func (k *KubernetesClient) CreateService(resourceFile string) (*v1.Service, error) { service := v1.Service{} data, err := ioutil.ReadFile(resourceFile) @@ -147,6 +170,7 @@ func (k *KubernetesClient) CreateService(resourceFile string) (*v1.Service, erro return createdService, err } +// DeleteService will delete the specified service name func (k *KubernetesClient) DeleteService(serviceName string) error { return k.client.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{}) } diff --git a/test/e2e/validatingwebhook/validating_webhook_suite_test.go b/test/e2e/validatingwebhook/validating_webhook_suite_test.go index 82337e0fd..344005784 100644 --- a/test/e2e/validatingwebhook/validating_webhook_suite_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_suite_test.go @@ -1,3 +1,19 @@ +/* + Copyright (C) 2020 Accurics, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package validatingwebhook_test import ( diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index b165cb902..bf338e517 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -1,3 +1,19 @@ +/* + Copyright (C) 2020 Accurics, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package validatingwebhook_test import ( @@ -21,7 +37,7 @@ import ( const ( certsFolder = "certs" - k8sWebhookApiKey = "K8S_WEBHOOK_API_KEY" + k8sWebhookAPIKey = "K8S_WEBHOOK_API_KEY" apiKeyValue = "accurics" defaultTimeout = 10 ) @@ -110,7 +126,7 @@ var _ = Describe("ValidatingWebhook", func() { err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, nil) Expect(err).NotTo(HaveOccurred()) - os.Setenv(k8sWebhookApiKey, apiKeyValue) + os.Setenv(k8sWebhookAPIKey, apiKeyValue) args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9010")) @@ -159,7 +175,7 @@ var _ = Describe("ValidatingWebhook", func() { err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) - os.Setenv(k8sWebhookApiKey, apiKeyValue) + os.Setenv(k8sWebhookAPIKey, apiKeyValue) args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9011")) @@ -208,7 +224,7 @@ var _ = Describe("ValidatingWebhook", func() { err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) - os.Setenv(k8sWebhookApiKey, apiKeyValue) + os.Setenv(k8sWebhookAPIKey, apiKeyValue) args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9012")) @@ -257,7 +273,7 @@ var _ = Describe("ValidatingWebhook", func() { err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) - os.Setenv(k8sWebhookApiKey, apiKeyValue) + os.Setenv(k8sWebhookAPIKey, apiKeyValue) args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9013")) diff --git a/test/e2e/validatingwebhook/validatingwebhook_utils.go b/test/e2e/validatingwebhook/validatingwebhook_utils.go index 346e58708..866f420e7 100644 --- a/test/e2e/validatingwebhook/validatingwebhook_utils.go +++ b/test/e2e/validatingwebhook/validatingwebhook_utils.go @@ -1,3 +1,19 @@ +/* + Copyright (C) 2020 Accurics, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package validatingwebhook import ( From 8302808a144e8f48c54f7e2de14def3e9a76d71b Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Wed, 12 May 2021 13:02:47 +0530 Subject: [PATCH 4/9] modify ip address logic --- pkg/http-server/webhook-scan-logs.go | 2 +- test/e2e/validatingwebhook/certgen.go | 15 +-------------- test/e2e/validatingwebhook/kubeclient.go | 2 +- .../validating_webhook_test.go | 2 +- .../validatingwebhook_utils.go | 18 ++++++++++++++++++ 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pkg/http-server/webhook-scan-logs.go b/pkg/http-server/webhook-scan-logs.go index b631aded6..c6fecf0d5 100644 --- a/pkg/http-server/webhook-scan-logs.go +++ b/pkg/http-server/webhook-scan-logs.go @@ -69,7 +69,7 @@ type webhookDisplayedShowLog struct { } func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: validating webhook' get logs request") + zap.S().Info("handle: validating webhook's get logs request") if !config.GetK8sAdmissionControl().Dashboard { apiErrorResponse(w, ErrDashboardDisabled.Error(), http.StatusBadRequest) diff --git a/test/e2e/validatingwebhook/certgen.go b/test/e2e/validatingwebhook/certgen.go index 50b2de4e3..83d7723f8 100644 --- a/test/e2e/validatingwebhook/certgen.go +++ b/test/e2e/validatingwebhook/certgen.go @@ -37,7 +37,7 @@ import ( func GenerateCertificates(certFilePath, privateKeyPath string) error { // ip address of the machine would be required to be added as // subject alternate name - ipAddr, err := getIP() + ipAddr, err := GetIP() if err != nil { return err } @@ -96,16 +96,3 @@ func pemBlockForKey(priv interface{}) *pem.Block { return nil } } - -// getIP finds preferred outbound ip of the machine -func getIP() (net.IP, error) { - conn, err := net.Dial("udp", "8.8.8.8:80") - if err != nil { - return nil, err - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP, nil -} diff --git a/test/e2e/validatingwebhook/kubeclient.go b/test/e2e/validatingwebhook/kubeclient.go index b662af494..c9a5add00 100644 --- a/test/e2e/validatingwebhook/kubeclient.go +++ b/test/e2e/validatingwebhook/kubeclient.go @@ -98,7 +98,7 @@ func (k *KubernetesClient) CreateValidatingWebhookConfiguration(webhookFile, cer webhook := &webhooks.Webhooks[0] webhook.ClientConfig.CABundle = certData - ip, err := getIP() + ip, err := GetIP() if err != nil { return nil, err } diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index bf338e517..a9e3116d8 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -339,7 +339,7 @@ func createPod(session *gexec.Session, webhookName string) { Expect(err).NotTo(HaveOccurred()) pod, err := kubeClient.CreatePod(podYamlAbsPath) - Eventually(session.Err, 10).Should(gbytes.Say("handle: validating webhook request")) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("handle: validating webhook request")) Expect(err).NotTo(HaveOccurred()) Expect(pod).NotTo(BeNil()) diff --git a/test/e2e/validatingwebhook/validatingwebhook_utils.go b/test/e2e/validatingwebhook/validatingwebhook_utils.go index 866f420e7..37ba40331 100644 --- a/test/e2e/validatingwebhook/validatingwebhook_utils.go +++ b/test/e2e/validatingwebhook/validatingwebhook_utils.go @@ -18,6 +18,7 @@ package validatingwebhook import ( "fmt" + "net" "os" "os/exec" "path/filepath" @@ -103,3 +104,20 @@ func CreateDefaultKindCluster() error { } return nil } + +// GetIP finds preferred outbound ip of the machine +func GetIP() (net.IP, error) { + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil, err + } + + for _, a := range addrs { + if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + return ipnet.IP.To4(), nil + } + } + } + return nil, fmt.Errorf("could not find ip address of the machine") +} From 9b7055d6db1176a4628b8d795be2f28d99f8658c Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Thu, 13 May 2021 21:21:11 +0530 Subject: [PATCH 5/9] tests for resource created with warnings --- .../validating_webhook_test.go | 129 ++++++++++++++++-- 1 file changed, 115 insertions(+), 14 deletions(-) diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index a9e3116d8..d1e13e546 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -204,7 +204,7 @@ var _ = Describe("ValidatingWebhook", func() { When("validating webhook config has 'denied-severity' specified", func() { - Context("service to be created violates a policy which has 'MEDIUM' seveirty", func() { + Context("service to be created violates a policy with specified denied severity", func() { var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() var session *gexec.Session var webhookConfig *admissionv1.ValidatingWebhookConfiguration @@ -245,15 +245,13 @@ var _ = Describe("ValidatingWebhook", func() { // remove the config file defer os.Remove(configFileName) - createService(session, webhookConfig.GetName()) + createService(session, webhookConfig.GetName(), true) }) }) }) }) - }) - When("validating webhook config has 'denied-categories' specified", func() { - Context("service to be created violates a policy which has 'Network Security' category", func() { + Context("service to be created violates a policy which doesn't have the desired severity", func() { var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() var session *gexec.Session var webhookConfig *admissionv1.ValidatingWebhookConfiguration @@ -267,7 +265,7 @@ var _ = Describe("ValidatingWebhook", func() { // create a config file with desired severity specified terrascanConfig := config.TerrascanConfig{ K8sAdmissionControl: config.K8sAdmissionControl{ - Categories: []string{"Network Security"}, + DeniedSeverity: "HIGH", }, } err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) @@ -294,7 +292,103 @@ var _ = Describe("ValidatingWebhook", func() { // remove the config file defer os.Remove(configFileName) - createService(session, webhookConfig.GetName()) + createService(session, webhookConfig.GetName(), false) + }) + }) + }) + }) + }) + + When("validating webhook config has 'denied-categories' specified", func() { + Context("service to be created violates the denied category", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + var port string + + It("server should start running on port 9014", func() { + port = "9014" + configFileName = "config5.toml" + + // create a config file with desired severity specified + terrascanConfig := config.TerrascanConfig{ + K8sAdmissionControl: config.K8sAdmissionControl{ + Categories: []string{"Network Security"}, + }, + } + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + Expect(err).NotTo(HaveOccurred()) + + os.Setenv(k8sWebhookAPIKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9014")) + }) + + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { + + webhookFilePath, err := filepath.Abs(filepath.Join(webhookYamlRelPath)) + Expect(err).NotTo(HaveOccurred()) + + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) + Expect(err).NotTo(HaveOccurred()) + }) + + When("service creation addmission requested is sent to server", func() { + It("server should get the addmission request to review and reject the request", func() { + // remove the config file + defer os.Remove(configFileName) + + createService(session, webhookConfig.GetName(), true) + }) + }) + }) + }) + + Context("service to be created does not violate the denied category", func() { + var outWriter, errWriter io.Writer = gbytes.NewBuffer(), gbytes.NewBuffer() + var session *gexec.Session + var webhookConfig *admissionv1.ValidatingWebhookConfiguration + var configFileName string + var port string + + It("server should start running on port 9015", func() { + port = "9015" + configFileName = "config6.toml" + + // create a config file with desired severity specified + terrascanConfig := config.TerrascanConfig{ + K8sAdmissionControl: config.K8sAdmissionControl{ + Categories: []string{"Doesn't Exist"}, + }, + } + err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + Expect(err).NotTo(HaveOccurred()) + + os.Setenv(k8sWebhookAPIKey, apiKeyValue) + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) + Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9015")) + }) + + When("request is made to add server as a validating webhook", func() { + It("should get registered with k8s cluster as validating webhook successfully", func() { + + webhookFilePath, err := filepath.Abs(filepath.Join(webhookYamlRelPath)) + Expect(err).NotTo(HaveOccurred()) + + webhookConfig, err = kubeClient.CreateValidatingWebhookConfiguration(webhookFilePath, certFileAbsPath, apiKeyValue, port) + Expect(err).NotTo(HaveOccurred()) + }) + + When("service creation addmission requested is sent to server", func() { + It("server should get the addmission request to review and reject the request", func() { + // remove the config file + defer os.Remove(configFileName) + + createService(session, webhookConfig.GetName(), false) }) }) }) @@ -305,21 +399,28 @@ var _ = Describe("ValidatingWebhook", func() { // createService creates a service and asserts for reject status, // and deletes the resources -func createService(session *gexec.Session, webhookName string) { +func createService(session *gexec.Session, webhookName string, shouldBeDenied bool) { serviceYamlAbsPath, err := filepath.Abs(filepath.Join(serviceYamlPath)) Expect(err).NotTo(HaveOccurred()) service, err := kubeClient.CreateService(serviceYamlAbsPath) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("handle: validating webhook request")) - Expect(err).To(HaveOccurred()) - if e, ok := err.(*k8serr.StatusError); ok { - Expect(e.Status().Code).To(BeNumerically("==", 403)) + if shouldBeDenied { + Expect(err).To(HaveOccurred()) + if e, ok := err.(*k8serr.StatusError); ok { + Expect(e.Status().Code).To(BeNumerically("==", 403)) + } else { + errMessage := fmt.Sprintf("expected error to be of type 'k8s.io/apimachinery/pkg/api/errors.StatusError', got of type %T", err) + Fail(errMessage) + } + Expect(service).To(BeNil()) } else { - errMessage := fmt.Sprintf("expected error to be of type 'k8s.io/apimachinery/pkg/api/errors.StatusError', got of type %T", err) - Fail(errMessage) + Expect(err).NotTo(HaveOccurred()) + + err = kubeClient.DeleteService(service.GetName()) + Expect(err).NotTo(HaveOccurred()) } - Expect(service).To(BeNil()) // delete validating webhook configuration err = kubeClient.DeleteValidatingWebhookConfiguration(webhookName) From e78d01baccddd1835453023334b0cda8e486d7b5 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Mon, 17 May 2021 21:31:15 +0530 Subject: [PATCH 6/9] incorporate review comments --- Makefile | 4 ++-- pkg/http-server/file-scan.go | 2 +- pkg/http-server/health.go | 2 +- pkg/http-server/remote-repo.go | 2 +- pkg/http-server/webhook-scan-logs.go | 2 +- pkg/http-server/webhook-scan.go | 2 +- ...alidating-webhook.sh => e2e-admission-control.sh} | 0 test/e2e/validatingwebhook/certgen.go | 2 +- test/e2e/validatingwebhook/kubeclient.go | 8 ++------ .../e2e/validatingwebhook/validating_webhook_test.go | 12 ++++++------ .../e2e/validatingwebhook/validatingwebhook_utils.go | 2 ++ 11 files changed, 18 insertions(+), 20 deletions(-) rename scripts/{e2e-validating-webhook.sh => e2e-admission-control.sh} (100%) diff --git a/Makefile b/Makefile index 9863b25a1..f2eb0807e 100644 --- a/Makefile +++ b/Makefile @@ -92,8 +92,8 @@ e2e-tests: build ./scripts/run-e2e.sh # run e2e validating webhook -e2e-validating-webhook: build - ./scripts/e2e-validating-webhook.sh +e2e-admission-control-tests: build + ./scripts/e2e-admission-control.sh # install kind install-kind: diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go index d9a6a4f19..3e041e04a 100644 --- a/pkg/http-server/file-scan.go +++ b/pkg/http-server/file-scan.go @@ -35,7 +35,7 @@ import ( // scanFile accepts uploaded file and runs scan on it func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: file scan request") + zap.S().Debug("handle: file scan request") // get url params params := mux.Vars(r) diff --git a/pkg/http-server/health.go b/pkg/http-server/health.go index d9231d6fa..6040fb05a 100644 --- a/pkg/http-server/health.go +++ b/pkg/http-server/health.go @@ -24,6 +24,6 @@ import ( // Health returns the health of the http server func (g *APIHandler) Health(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: health check request") + zap.S().Debug("handle: health check request") w.WriteHeader(http.StatusOK) } diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go index 5734da2b9..a07946c3c 100644 --- a/pkg/http-server/remote-repo.go +++ b/pkg/http-server/remote-repo.go @@ -50,7 +50,7 @@ type scanRemoteRepoReq struct { // scanRemoteRepo downloads the remote Iac repository and scans it for // violations func (g *APIHandler) scanRemoteRepo(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: remote repository scan request") + zap.S().Debug("handle: remote repository scan request") // get url params params := mux.Vars(r) diff --git a/pkg/http-server/webhook-scan-logs.go b/pkg/http-server/webhook-scan-logs.go index c6fecf0d5..082a01421 100644 --- a/pkg/http-server/webhook-scan-logs.go +++ b/pkg/http-server/webhook-scan-logs.go @@ -69,7 +69,7 @@ type webhookDisplayedShowLog struct { } func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: validating webhook's get logs request") + zap.S().Debug("handle: validating webhook's get logs request") if !config.GetK8sAdmissionControl().Dashboard { apiErrorResponse(w, ErrDashboardDisabled.Error(), http.StatusBadRequest) diff --git a/pkg/http-server/webhook-scan.go b/pkg/http-server/webhook-scan.go index a3c55ea8d..49a26dbab 100644 --- a/pkg/http-server/webhook-scan.go +++ b/pkg/http-server/webhook-scan.go @@ -31,7 +31,7 @@ import ( // validateK8SWebhook handles the incoming validating admission webhook from kubernetes API server func (g *APIHandler) validateK8SWebhook(w http.ResponseWriter, r *http.Request) { - zap.S().Info("handle: validating webhook request") + zap.S().Debug("handle: validating webhook request") var ( params = mux.Vars(r) diff --git a/scripts/e2e-validating-webhook.sh b/scripts/e2e-admission-control.sh similarity index 100% rename from scripts/e2e-validating-webhook.sh rename to scripts/e2e-admission-control.sh diff --git a/test/e2e/validatingwebhook/certgen.go b/test/e2e/validatingwebhook/certgen.go index 83d7723f8..f1f6343ec 100644 --- a/test/e2e/validatingwebhook/certgen.go +++ b/test/e2e/validatingwebhook/certgen.go @@ -50,7 +50,7 @@ func GenerateCertificates(certFilePath, privateKeyPath string) error { template := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ - Organization: []string{"Accurics"}, + Organization: []string{"acme.org"}, Country: []string{"IN"}, }, IPAddresses: []net.IP{ipAddr}, diff --git a/test/e2e/validatingwebhook/kubeclient.go b/test/e2e/validatingwebhook/kubeclient.go index c9a5add00..938fdd808 100644 --- a/test/e2e/validatingwebhook/kubeclient.go +++ b/test/e2e/validatingwebhook/kubeclient.go @@ -57,7 +57,6 @@ func NewKubernetesClient() (*KubernetesClient, error) { func (k *KubernetesClient) getK8sClient() (*kubernetes.Clientset, error) { home, err := homedir.Dir() if err != nil { - fmt.Println("home directory not found", err) return nil, fmt.Errorf("home directory not found, error: %s", err.Error()) } @@ -110,7 +109,6 @@ func (k *KubernetesClient) CreateValidatingWebhookConfiguration(webhookFile, cer createdWebhookConfig, err := admr.ValidatingWebhookConfigurations().Create(context.TODO(), &webhooks, metav1.CreateOptions{}) if err != nil { - fmt.Println(err) return nil, err } return createdWebhookConfig, nil @@ -137,10 +135,9 @@ func (k *KubernetesClient) CreatePod(resourceFile string) (*v1.Pod, error) { createdPod, err := k.client.CoreV1().Pods(namespace).Create(context.TODO(), &pod, metav1.CreateOptions{}) if err != nil { - fmt.Println(err) return nil, err } - return createdPod, err + return createdPod, nil } // DeletePod will delete the specified pod name @@ -164,10 +161,9 @@ func (k *KubernetesClient) CreateService(resourceFile string) (*v1.Service, erro createdService, err := k.client.CoreV1().Services(namespace).Create(context.TODO(), &service, metav1.CreateOptions{}) if err != nil { - fmt.Println(err) return nil, err } - return createdService, err + return createdService, nil } // DeleteService will delete the specified service name diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index d1e13e546..ed34b02b8 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -127,7 +127,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9010")) }) @@ -176,7 +176,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9011")) }) @@ -225,7 +225,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9012")) }) @@ -272,7 +272,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9013")) }) @@ -321,7 +321,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9014")) }) @@ -368,7 +368,7 @@ var _ = Describe("ValidatingWebhook", func() { Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) - args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port} + args := []string{"server", "-c", configFileName, "--cert-path", certFileAbsPath, "--key-path", privKeyFileAbsPath, "-p", port, "-l", "debug"} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, args...) Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9015")) }) diff --git a/test/e2e/validatingwebhook/validatingwebhook_utils.go b/test/e2e/validatingwebhook/validatingwebhook_utils.go index 37ba40331..7769a2dcc 100644 --- a/test/e2e/validatingwebhook/validatingwebhook_utils.go +++ b/test/e2e/validatingwebhook/validatingwebhook_utils.go @@ -88,6 +88,7 @@ func CreateCertificate(certsFolder, certFileName, privKeyFileName string) (strin // DeleteDefaultKindCluster deletes the default kind cluster func DeleteDefaultKindCluster() error { cmd := exec.Command("kind", "delete", "cluster") + cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return err @@ -98,6 +99,7 @@ func DeleteDefaultKindCluster() error { // CreateDefaultKindCluster creates the default kind cluster func CreateDefaultKindCluster() error { cmd := exec.Command("kind", "create", "cluster") + cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return err From b6a68c13c23d6ddf5b757ba7b8a16c014df8763c Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Tue, 18 May 2021 13:27:09 +0530 Subject: [PATCH 7/9] add help in makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index f2eb0807e..e8deff520 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ help: @echo "test\n\texecute unit and integration tests" @echo "unit-tests\n\texecute unit tests" @echo "e2e-tests\n\texecute e2e tests" + @echo "e2e-admission-control-tests\n\texecute e2e admission control tests" @echo "validate\n\trun all validations" # build terrascan binary From 8ceb98bfdeb17e3a4128b932996612b14d1b6091 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Tue, 18 May 2021 14:42:08 +0530 Subject: [PATCH 8/9] incorporate review comments --- .../e2e/validatingwebhook/validating_webhook_test.go | 12 ++++++------ .../e2e/validatingwebhook/validatingwebhook_utils.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index ed34b02b8..447c52c45 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -123,7 +123,7 @@ var _ = Describe("ValidatingWebhook", func() { It("server should start running on port 9010", func() { configFileName = "config1.toml" // create a config file with default config values - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, nil) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, nil) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) @@ -172,7 +172,7 @@ var _ = Describe("ValidatingWebhook", func() { SaveRequests: true, }, } - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) @@ -221,7 +221,7 @@ var _ = Describe("ValidatingWebhook", func() { DeniedSeverity: "MEDIUM", }, } - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) @@ -268,7 +268,7 @@ var _ = Describe("ValidatingWebhook", func() { DeniedSeverity: "HIGH", }, } - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) @@ -317,7 +317,7 @@ var _ = Describe("ValidatingWebhook", func() { Categories: []string{"Network Security"}, }, } - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) @@ -364,7 +364,7 @@ var _ = Describe("ValidatingWebhook", func() { Categories: []string{"Doesn't Exist"}, }, } - err := validatingwebhook.CreateConfigFile(configFileName, policyRootRelPath, &terrascanConfig) + err := validatingwebhook.CreateTerrascanConfigFile(configFileName, policyRootRelPath, &terrascanConfig) Expect(err).NotTo(HaveOccurred()) os.Setenv(k8sWebhookAPIKey, apiKeyValue) diff --git a/test/e2e/validatingwebhook/validatingwebhook_utils.go b/test/e2e/validatingwebhook/validatingwebhook_utils.go index 7769a2dcc..3c250507e 100644 --- a/test/e2e/validatingwebhook/validatingwebhook_utils.go +++ b/test/e2e/validatingwebhook/validatingwebhook_utils.go @@ -29,8 +29,8 @@ import ( "github.com/pelletier/go-toml" ) -// CreateConfigFile creates a config file with test policy path -func CreateConfigFile(configFileName, policyRootRelPath string, terrascanConfig *config.TerrascanConfig) error { +// CreateTerrascanConfigFile creates a config file with test policy path +func CreateTerrascanConfigFile(configFileName, policyRootRelPath string, terrascanConfig *config.TerrascanConfig) error { policyAbsPath, err := filepath.Abs(policyRootRelPath) if err != nil { return err From fa106ce026f041734c819bf3cbec4be0cce43154 Mon Sep 17 00:00:00 2001 From: Pankaj Patil Date: Tue, 18 May 2021 19:16:51 +0530 Subject: [PATCH 9/9] added tests for logs endpoint --- .../validating_webhook_test.go | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/e2e/validatingwebhook/validating_webhook_test.go b/test/e2e/validatingwebhook/validating_webhook_test.go index 447c52c45..b202c1d8c 100644 --- a/test/e2e/validatingwebhook/validating_webhook_test.go +++ b/test/e2e/validatingwebhook/validating_webhook_test.go @@ -19,12 +19,14 @@ package validatingwebhook_test import ( "fmt" "io" + "net/http" "os" "path/filepath" "time" "github.com/accurics/terrascan/pkg/config" "github.com/accurics/terrascan/pkg/utils" + "github.com/accurics/terrascan/test/e2e/server" "github.com/accurics/terrascan/test/e2e/validatingwebhook" "github.com/accurics/terrascan/test/helper" . "github.com/onsi/ginkgo" @@ -132,6 +134,34 @@ var _ = Describe("ValidatingWebhook", func() { Eventually(session.Err, defaultTimeout).Should(gbytes.Say("http server listening at port 9010")) }) + Context("in blind mode, log end points return error response", func() { + port := "9010" + myIP, err := validatingwebhook.GetIP() + When("request is made to the get a single log endpoint", func() { + It("should return a 400 bad request response", func() { + Expect(err).NotTo(HaveOccurred()) + + requestURL := fmt.Sprintf("http://%s:%s/k8s/webhooks/logs/%s", myIP.To4(), port, apiKeyValue) + resp, err := server.MakeHTTPRequest("GET", requestURL) + Expect(err).NotTo(HaveOccurred()) + Expect(resp).NotTo(BeNil()) + Expect(resp.StatusCode).To(BeIdenticalTo(http.StatusBadRequest)) + }) + }) + + When("request is made to the get a single log endpoint", func() { + It("should return a 400 bad request response", func() { + Expect(err).NotTo(HaveOccurred()) + + requestURL := fmt.Sprintf("http://%s:%s/k8s/webhooks/%s/logs", myIP.To4(), port, apiKeyValue) + resp, err := server.MakeHTTPRequest("GET", requestURL) + Expect(err).NotTo(HaveOccurred()) + Expect(resp).NotTo(BeNil()) + Expect(resp.StatusCode).To(BeIdenticalTo(http.StatusBadRequest)) + }) + }) + }) + When("request is made to add server as a validating webhook", func() { It("should get registered with k8s cluster as validating webhook successfully", func() {