diff --git a/go.mod b/go.mod index cab6990b7..a3c3c0bd1 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/zclconf/go-cty v1.8.3 go.uber.org/zap v1.16.0 - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c + golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 golang.org/x/tools v0.1.5 // indirect gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 0d5353765..34aacde23 100644 --- a/go.sum +++ b/go.sum @@ -1725,11 +1725,10 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/iac-providers/kubernetes/v1/extract-images.go b/pkg/iac-providers/kubernetes/v1/extract-images.go new file mode 100644 index 000000000..d28ef3923 --- /dev/null +++ b/pkg/iac-providers/kubernetes/v1/extract-images.go @@ -0,0 +1,149 @@ +/* + 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 k8sv1 + +import ( + "encoding/json" + + "github.com/accurics/terrascan/pkg/iac-providers/output" + "github.com/accurics/terrascan/pkg/utils" + yamltojson "github.com/ghodss/yaml" + "github.com/pkg/errors" + "go.uber.org/zap" + k8sappsv1 "k8s.io/api/apps/v1" + k8sbatchv1 "k8s.io/api/batch/v1" + k8sbatchv1beta1 "k8s.io/api/batch/v1beta1" + k8scorev1 "k8s.io/api/core/v1" +) + +func (k *K8sV1) extractContainerImages(kind string, doc *utils.IacDocument) ([]output.ContainerNameAndImage, []output.ContainerNameAndImage, error) { + var containerImages = make([]output.ContainerNameAndImage, 0) + var initContainerImages = make([]output.ContainerNameAndImage, 0) + var data []byte + var err error + + if doc.Data == nil { + return containerImages, initContainerImages, errors.Errorf("document does not have any resource data for unmarshalling") + } + + if doc.Type == utils.YAMLDoc { + data, err = yamltojson.YAMLToJSON(doc.Data) + if err != nil { + return nil, nil, err + } + } else { + data = doc.Data + } + + switch kind { + case "Pod": + pod := k8scorev1.Pod{} + err = json.Unmarshal(data, &pod) + if err != nil { + err := errors.Errorf("error unmarshalling pod: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(pod.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(pod.Spec.InitContainers)...) + + case "Deployment": + deployment := k8sappsv1.Deployment{} + err = json.Unmarshal(data, &deployment) + if err != nil { + err := errors.Errorf("error unmarshalling deployment: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(deployment.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(deployment.Spec.Template.Spec.InitContainers)...) + + case "ReplicationController": + rc := k8scorev1.ReplicationController{} + err = json.Unmarshal(data, &rc) + if err != nil { + err := errors.Errorf("error unmarshalling replicationcontroller: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(rc.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(rc.Spec.Template.Spec.InitContainers)...) + + case "Job": + job := k8sbatchv1.Job{} + err = json.Unmarshal(data, &job) + if err != nil { + err := errors.Errorf("error unmarshalling job: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(job.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(job.Spec.Template.Spec.InitContainers)...) + + case "CronJob": + cronjob := k8sbatchv1beta1.CronJob{} + err = json.Unmarshal(data, &cronjob) + if err != nil { + err := errors.Errorf("error unmarshalling cronjob: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(cronjob.Spec.JobTemplate.Spec.Template.Spec.InitContainers)...) + case "StatefulSet": + ss := k8sappsv1.StatefulSet{} + err = json.Unmarshal(data, &ss) + if err != nil { + err := errors.Errorf("error unmarshalling statefulset: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(ss.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(ss.Spec.Template.Spec.InitContainers)...) + case "ReplicaSet": + rs := k8sappsv1.ReplicaSet{} + err = json.Unmarshal(data, &rs) + if err != nil { + err := errors.Errorf("error unmarshalling replicaset: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(rs.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(rs.Spec.Template.Spec.InitContainers)...) + case "DaemonSet": + ds := k8sappsv1.DaemonSet{} + err = json.Unmarshal(data, &ds) + if err != nil { + err := errors.Errorf("error unmarshalling daemonset: %v", err) + zap.S().Errorf(err.Error()) + return nil, nil, err + } + containerImages = append(containerImages, readContainers(ds.Spec.Template.Spec.Containers)...) + initContainerImages = append(initContainerImages, readContainers(ds.Spec.Template.Spec.InitContainers)...) + default: + zap.S().Debugf("the container image extraction for kubernetes workload of kind %s is not supported.", kind) + } + return containerImages, initContainerImages, nil +} + +//readContainers prepares list of containers and init containers from k8scorev1.Container object +func readContainers(containers []k8scorev1.Container) (containerImages []output.ContainerNameAndImage) { + for _, container := range containers { + containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) + } + return +} diff --git a/pkg/iac-providers/kubernetes/v1/extract-images_test.go b/pkg/iac-providers/kubernetes/v1/extract-images_test.go new file mode 100644 index 000000000..1df393ed3 --- /dev/null +++ b/pkg/iac-providers/kubernetes/v1/extract-images_test.go @@ -0,0 +1,182 @@ +/* + 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 k8sv1 + +import ( + "reflect" + "testing" + + "github.com/accurics/terrascan/pkg/iac-providers/kubernetes/v1/testdata" + "github.com/accurics/terrascan/pkg/iac-providers/output" + "github.com/accurics/terrascan/pkg/utils" +) + +func TestK8sV1ExtractContainerImages(t *testing.T) { + type args struct { + doc *utils.IacDocument + kind string + } + tests := []struct { + name string + k *K8sV1 + args args + wantContainerImageList []output.ContainerNameAndImage + wantInitContainerImageList []output.ContainerNameAndImage + wantErr bool + }{ + { + name: "empty document object", + args: args{ + doc: &utils.IacDocument{}, + kind: "CRD", + }, + wantErr: true, + wantContainerImageList: []output.ContainerNameAndImage{}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "pod json document object", + args: args{ + doc: &utils.IacDocument{ + Type: "json", + Data: testdata.PodJSONTemplate, + }, + kind: "Pod", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "healthz", Image: "k8s.gcr.io/exechealthz-amd64:1.2"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "pod yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.PodYAMLTemplate, + }, + kind: "Pod", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "myapp-container", Image: "nginx"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{{Name: "myapp-container", Image: "busybox"}}, + }, + { + name: "cronjob yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.CronJobYAMLTemplate, + }, + kind: "CronJob", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "hello", Image: "busybox"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "job yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.JobYAMLTemplate, + }, + kind: "Job", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "c", Image: "gcr.io/terrascan/job-wq-1"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "deployment yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.DeploymentYAMLTemplate, + }, + kind: "Deployment", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "nginx", Image: "nginx:1.14.2"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{{Name: "init", Image: "busybox"}}, + }, + { + name: "daemonset yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.DaemonSetYAMLTemplate, + }, + kind: "DaemonSet", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "fluentd-elasticsearch", Image: "quay.io/fluentd_elasticsearch/fluentd:v2.5.2"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "replicaset yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.ReplicaSetYAMLTemplate, + }, + kind: "ReplicaSet", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "php-redis", Image: "gcr.io/google_samples/gb-frontend:v3"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + { + name: "replicationcontroller yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.ReplicationControllerTemplate, + }, + kind: "ReplicationController", + }, + wantContainerImageList: []output.ContainerNameAndImage{ + {Name: "nginx", Image: "nginx:latest"}, + {Name: "sidecar1", Image: "sidecar-image-1"}, + {Name: "sidecar2", Image: "sidecar-image-2"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{ + {Name: "init1", Image: "init-image-1"}, + {Name: "init2", Image: "init-image-2"}, + {Name: "init3", Image: "init-image-3"}}, + }, + { + name: "statefulSet yaml document object", + args: args{ + doc: &utils.IacDocument{ + Type: "yaml", + Data: testdata.StatefulSetTemplate, + }, + kind: "StatefulSet", + }, + wantContainerImageList: []output.ContainerNameAndImage{{Name: "nginx", Image: "k8s.gcr.io/nginx-slim:0.8"}}, + wantInitContainerImageList: []output.ContainerNameAndImage{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + k := &K8sV1{} + gotContainerImageList, gotInitContainerImageList, err := k.extractContainerImages(tt.args.kind, tt.args.doc) + if (err != nil) != tt.wantErr { + t.Errorf("K8sV1.extractContainerImages() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotContainerImageList, tt.wantContainerImageList) { + t.Errorf("K8sV1.extractResource() got = %v, want %v", gotContainerImageList, tt.wantContainerImageList) + } + if !reflect.DeepEqual(gotInitContainerImageList, tt.wantInitContainerImageList) { + t.Errorf("K8sV1.extractResource() got InitContainerImageList = %v, want %v", gotInitContainerImageList, tt.wantInitContainerImageList) + } + }) + } +} diff --git a/pkg/iac-providers/kubernetes/v1/load-dir.go b/pkg/iac-providers/kubernetes/v1/load-dir.go index faeeb85a6..b8300994d 100644 --- a/pkg/iac-providers/kubernetes/v1/load-dir.go +++ b/pkg/iac-providers/kubernetes/v1/load-dir.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 k8sv1 import ( diff --git a/pkg/iac-providers/kubernetes/v1/load-file.go b/pkg/iac-providers/kubernetes/v1/load-file.go index a672d1c5d..ddc76857b 100644 --- a/pkg/iac-providers/kubernetes/v1/load-file.go +++ b/pkg/iac-providers/kubernetes/v1/load-file.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 k8sv1 import ( diff --git a/pkg/iac-providers/kubernetes/v1/normalize.go b/pkg/iac-providers/kubernetes/v1/normalize.go index 1cca3485c..78b5f9f02 100644 --- a/pkg/iac-providers/kubernetes/v1/normalize.go +++ b/pkg/iac-providers/kubernetes/v1/normalize.go @@ -19,7 +19,6 @@ package k8sv1 import ( "encoding/json" "fmt" - "github.com/accurics/terrascan/pkg/iac-providers/output" "github.com/accurics/terrascan/pkg/utils" yamltojson "github.com/ghodss/yaml" @@ -112,7 +111,9 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error } var resourceConfig output.ResourceConfig - + resourceConfig.ContainerImages = make([]output.ContainerNameAndImage, 0) + resourceConfig.InitContainerImages = make([]output.ContainerNameAndImage, 0) + var containerImages, initContainerImages []output.ContainerNameAndImage resourceConfig.Type = k.getNormalizedName(resource.Kind) switch resource.Kind { @@ -122,8 +123,13 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error // non-namespaced resources case "ClusterRole": fallthrough - case "Namespace": - resourceConfig.ID = resourceConfig.Type + "." + resource.Metadata.NameOrGenerateName() + // pod and all kinds of workloads + case "Pod", "Deployment", "ReplicaSet", "ReplicationController", "Job", "CronJob", "StatefulSet", "DaemonSet": + containerImages, initContainerImages, err = k.extractContainerImages(resource.Kind, doc) + if err != nil { + return nil, err + } + fallthrough default: // namespaced-resources namespace := resource.Metadata.Namespace @@ -134,6 +140,9 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error resourceConfig.ID = resourceConfig.Type + "." + resource.Metadata.NameOrGenerateName() + "-" + namespace } + resourceConfig.ContainerImages = append(resourceConfig.ContainerImages, containerImages...) + resourceConfig.InitContainerImages = append(resourceConfig.InitContainerImages, initContainerImages...) + // read and update skip rules, if present skipRules := utils.ReadSkipRulesFromMap(resource.Metadata.Annotations, resourceConfig.ID) if skipRules != nil { diff --git a/pkg/iac-providers/kubernetes/v1/normalize_test.go b/pkg/iac-providers/kubernetes/v1/normalize_test.go index 4700349f6..bc28a2d5e 100644 --- a/pkg/iac-providers/kubernetes/v1/normalize_test.go +++ b/pkg/iac-providers/kubernetes/v1/normalize_test.go @@ -237,7 +237,9 @@ func TestK8sV1Normalize(t *testing.T) { }, }, }, - SkipRules: []output.SkipRule{testSkipRule}, + SkipRules: []output.SkipRule{testSkipRule}, + ContainerImages: []output.ContainerNameAndImage{{Name: "myapp-container", Image: "busybox"}}, + InitContainerImages: []output.ContainerNameAndImage{}, }, }, { @@ -271,7 +273,9 @@ func TestK8sV1Normalize(t *testing.T) { }, }, }, - SkipRules: []output.SkipRule{testSkipRule}, + SkipRules: []output.SkipRule{testSkipRule}, + ContainerImages: []output.ContainerNameAndImage{}, + InitContainerImages: []output.ContainerNameAndImage{}, }, }, } @@ -283,8 +287,9 @@ func TestK8sV1Normalize(t *testing.T) { t.Errorf("K8sV1.Normalize() error = %v, wantErr %v", err, tt.wantErr) return } + if !reflect.DeepEqual(got, tt.want) { - t.Errorf("K8sV1.Normalize() got = %+v, want = %+v", got, tt.want) + t.Errorf("K8sV1.Normalize() got = %+v, want = %+v", *got, *(tt.want)) } }) } diff --git a/pkg/iac-providers/kubernetes/v1/testdata/k8s_templates.go b/pkg/iac-providers/kubernetes/v1/testdata/k8s_templates.go new file mode 100644 index 000000000..d093e104b --- /dev/null +++ b/pkg/iac-providers/kubernetes/v1/testdata/k8s_templates.go @@ -0,0 +1,248 @@ +/* + 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 testdata + +var ( + // PodJSONTemplate .. + PodJSONTemplate = []byte(`{ + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "simple" + }, + "spec": { + "containers": [ + { + "name": "healthz", + "image": "k8s.gcr.io/exechealthz-amd64:1.2", + "args": [ + "-cmd=nslookup localhost" + ], + "ports": [ + { + "containerPort": 8080, + "protocol": "TCP" + } + ] + } + ] + } + }`) + // PodYAMLTemplate .. + PodYAMLTemplate = []byte(`apiVersion: v1 +kind: Pod +metadata: + name: myapp-pod + annotations: +spec: + initContainers: + - name: myapp-container + image: busybox + containers: + - name: myapp-container + image: nginx`) + // CronJobYAMLTemplate .. + CronJobYAMLTemplate = []byte(`apiVersion: batch/v1 +kind: CronJob +metadata: + name: hello +spec: + schedule: "*/1 * * * *" + jobTemplate: + spec: + template: + spec: + containers: + - name: hello + image: busybox + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - date; echo Hello from the Kubernetes cluster + restartPolicy: OnFailure`) + // JobYAMLTemplate .. + JobYAMLTemplate = []byte(`apiVersion: batch/v1 +kind: Job +metadata: + name: job-wq-1 +spec: + completions: 8 + parallelism: 2 + template: + metadata: + name: job-wq-1 + spec: + containers: + - name: c + image: gcr.io/terrascan/job-wq-1 + env: + - name: BROKER_URL + value: amqp://guest:guest@rabbitmq-service:5672 + - name: QUEUE + value: job1 + restartPolicy: OnFailure`) + // DeploymentYAMLTemplate .. + DeploymentYAMLTemplate = []byte(`apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: 2 # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + spec: + initContainers: + - name: init + image: busybox + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +`) + // DaemonSetYAMLTemplate .. + DaemonSetYAMLTemplate = []byte(`apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: fluentd-elasticsearch + namespace: kube-system + labels: + k8s-app: fluentd-logging +spec: + selector: + matchLabels: + name: fluentd-elasticsearch + template: + metadata: + labels: + name: fluentd-elasticsearch + spec: + tolerations: + # this toleration is to have the daemonset runnable on master nodes + # remove it if your masters can't run pods + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + containers: + - name: fluentd-elasticsearch + image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 + resources: + limits: + memory: 200Mi + requests: + cpu: 100m + memory: 200Mi + volumeMounts: + - name: varlog + mountPath: /var/log + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + terminationGracePeriodSeconds: 30 + volumes: + - name: varlog + hostPath: + path: /var/log + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers`) + // ReplicaSetYAMLTemplate .. + ReplicaSetYAMLTemplate = []byte(`apiVersion: apps/v1 +kind: ReplicaSet +metadata: + name: frontend + labels: + app: guestbook + tier: frontend +spec: + # modify replicas according to your case + replicas: 3 + selector: + matchLabels: + tier: frontend + template: + metadata: + labels: + tier: frontend + spec: + containers: + - name: php-redis + image: gcr.io/google_samples/gb-frontend:v3 +`) + // ReplicationControllerTemplate .. + ReplicationControllerTemplate = []byte(`apiVersion: v1 +kind: ReplicationController +metadata: + name: nginx +spec: + replicas: 3 + selector: + app: nginx + template: + metadata: + name: nginx + labels: + app: nginx + spec: + initContainers: + - name: init1 + image: init-image-1 + - name: init2 + image: init-image-2 + - name: init3 + image: init-image-3 + containers: + - name: nginx + image: nginx:latest + ports: + - containerPort: 80 + - name: sidecar1 + image: sidecar-image-1 + - name: sidecar2 + image: sidecar-image-2 + +`) + + // StatefulSetTemplate ... + StatefulSetTemplate = []byte(`apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: web +spec: + serviceName: "nginx" + replicas: 2 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: k8s.gcr.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web`) +) diff --git a/pkg/iac-providers/output/types.go b/pkg/iac-providers/output/types.go index 9c0bb725b..5ca7715a3 100644 --- a/pkg/iac-providers/output/types.go +++ b/pkg/iac-providers/output/types.go @@ -35,9 +35,17 @@ type ResourceConfig struct { // SkipRules will hold the rules to be skipped for the resource. // Each iac provider should append the rules to be skipped for a resource, // while extracting resource from the iac files - SkipRules []SkipRule `json:"skip_rules" yaml:"skip_rules"` - MaxSeverity string `json:"max_severity"` - MinSeverity string `json:"min_severity"` + SkipRules []SkipRule `json:"skip_rules" yaml:"skip_rules"` + MaxSeverity string `json:"max_severity"` + MinSeverity string `json:"min_severity"` + ContainerImages []ContainerNameAndImage `json:"container_images,omitempty"` + InitContainerImages []ContainerNameAndImage `json:"init_container_images,omitempty"` +} + +// ContainerNameAndImage container name and image +type ContainerNameAndImage struct { + Name string `json:"name"` + Image string `json:"image"` } // SkipRule struct will hold the skipped rule and any comment for the skipped rule diff --git a/pkg/iac-providers/terraform/v12/testdata/tfjson/config1.json b/pkg/iac-providers/terraform/v12/testdata/tfjson/config1.json index 44e48961a..038b28c0c 100644 --- a/pkg/iac-providers/terraform/v12/testdata/tfjson/config1.json +++ b/pkg/iac-providers/terraform/v12/testdata/tfjson/config1.json @@ -213,4 +213,4 @@ "min_severity": "" } ] -} \ No newline at end of file +} diff --git a/pkg/iac-providers/terraform/v12/testdata/tfjson/dummyconfig.json b/pkg/iac-providers/terraform/v12/testdata/tfjson/dummyconfig.json index b8cc927d6..a7fb59c70 100644 --- a/pkg/iac-providers/terraform/v12/testdata/tfjson/dummyconfig.json +++ b/pkg/iac-providers/terraform/v12/testdata/tfjson/dummyconfig.json @@ -94,4 +94,4 @@ "min_severity": "" } ] -} \ No newline at end of file +} diff --git a/pkg/iac-providers/terraform/v14/testdata/tfjson/config1.json b/pkg/iac-providers/terraform/v14/testdata/tfjson/config1.json index 44e48961a..038b28c0c 100644 --- a/pkg/iac-providers/terraform/v14/testdata/tfjson/config1.json +++ b/pkg/iac-providers/terraform/v14/testdata/tfjson/config1.json @@ -213,4 +213,4 @@ "min_severity": "" } ] -} \ No newline at end of file +} diff --git a/pkg/iac-providers/terraform/v14/testdata/tfjson/dummyconfig.json b/pkg/iac-providers/terraform/v14/testdata/tfjson/dummyconfig.json index b8cc927d6..a7fb59c70 100644 --- a/pkg/iac-providers/terraform/v14/testdata/tfjson/dummyconfig.json +++ b/pkg/iac-providers/terraform/v14/testdata/tfjson/dummyconfig.json @@ -94,4 +94,4 @@ "min_severity": "" } ] -} \ No newline at end of file +} diff --git a/pkg/writer/yaml_test.go b/pkg/writer/yaml_test.go index d1f2fab38..73eacea7d 100644 --- a/pkg/writer/yaml_test.go +++ b/pkg/writer/yaml_test.go @@ -84,7 +84,9 @@ const ( policy: ${module.m2.fullbucketpolicy} skip_rules: [] maxseverity: "" - minseverity: ""` + minseverity: "" + containerimages: [] + initcontainerimages: []` scanTestOutputYAML = `results: violations: