-
Notifications
You must be signed in to change notification settings - Fork 497
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
resourceconfig output should include container image list while scann…
…ing for k8s family
- Loading branch information
1 parent
d3c529e
commit 571242c
Showing
15 changed files
with
633 additions
and
258 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
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 | ||
} | ||
for _, container := range pod.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range pod.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range deployment.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range deployment.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range rc.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range rc.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range job.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range job.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range cronjob.Spec.JobTemplate.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range ss.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range ss.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range rs.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range rs.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
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 | ||
} | ||
for _, container := range ds.Spec.Template.Spec.Containers { | ||
containerImages = append(containerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
for _, container := range ds.Spec.Template.Spec.InitContainers { | ||
initContainerImages = append(initContainerImages, output.ContainerNameAndImage{Name: container.Name, Image: container.Image}) | ||
} | ||
default: | ||
zap.S().Debugf("the container image extraction for kubernetes workload of kind %s is not supported.", kind) | ||
} | ||
return containerImages, initContainerImages, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package k8sv1 | ||
|
||
import ( | ||
"github.com/accurics/terrascan/pkg/iac-providers/kubernetes/v1/testdata" | ||
"github.com/accurics/terrascan/pkg/iac-providers/output" | ||
"github.com/accurics/terrascan/pkg/utils" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
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"}}, | ||
}, | ||
} | ||
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 = %v, want %v", gotInitContainerImageList, tt.wantInitContainerImageList) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.