Skip to content

Commit

Permalink
Merge pull request #309 from accurics/add-config-only-output
Browse files Browse the repository at this point in the history
add support to print resource config as an output
  • Loading branch information
Willie authored Sep 3, 2020
2 parents f98373b + 1edf439 commit 618475a
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 25 deletions.
49 changes: 49 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Usage:
terrascan scan [flags]

Flags:
--config-only will output resource config (should only be used for debugging purposes)
-h, --help help for scan
-d, --iac-dir string path to a directory containing one or more IaC files (default ".")
-f, --iac-file string path to a single IaC file
Expand All @@ -121,6 +122,54 @@ By default Terrascan will output YAML. This can be changed to JSON or XML by usi

Terrascan will exit 3 if any issues are found.

### CLI Output types
#### Violations
Terrascan's default output is a list of violations present in the scanned IaC.
``` Bash
$ terrascan scan -t aws
results:
violations:
- rule_name: scanOnPushDisabled
description: Unscanned images may contain vulnerabilities
rule_id: AWS.ECR.DataSecurity.High.0578
severity: MEDIUM
category: Data Security
resource_name: scanOnPushDisabled
resource_type: aws_ecr_repository
file: ecr.tf
line: 1
count:
low: 0
medium: 1
high: 0
total: 1
```
##### Resource Config
Terrascan while scanning the IaC, loads all the IaC files, creates a list of resource configs and then processes this list to report violations. For debugging purposes, it possible to print this resource configs list as an output by providing the `--config-only` flag to the `terrascan scan` command.
``` Bash
$ terrascan scan -t aws --config-only
aws_ecr_repository:
- id: aws_ecr_repository.scanOnPushDisabled
name: scanOnPushDisabled
source: ecr.tf
line: 1
type: aws_ecr_repository
config:
image_scanning_configuration:
- scan_on_push:
value: {}
image_tag_mutability: MUTABLE
name: test
- id: aws_ecr_repository.scanOnPushNoSet
name: scanOnPushNoSet
source: ecr.tf
line: 10
type: aws_ecr_repository
config:
image_tag_mutability: MUTABLE
name: test
```

### Server mode
Server mode will execute Terrascan's API server. This is useful when using Terrascan to enforce policies in a centralized way. By default the server will be started listening in port 9010 and supports the following routes:

Expand Down
13 changes: 8 additions & 5 deletions pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

// Run executes terrascan in CLI mode
func Run(iacType, iacVersion, cloudType, iacFilePath, iacDirPath, configFile,
policyPath, format string) {
policyPath, format string, configOnly bool) {

// create a new runtime executor for processing IaC
executor, err := runtime.NewExecutor(iacType, iacVersion, cloudType, iacFilePath,
Expand All @@ -35,13 +35,16 @@ func Run(iacType, iacVersion, cloudType, iacFilePath, iacDirPath, configFile,
}

// executor output
violations, err := executor.Execute()
results, err := executor.Execute()
if err != nil {
return
}
writer.Write(format, violations, os.Stdout)

if violations.ViolationStore.Count.TotalCount != 0 {
if configOnly {
writer.Write(format, results.ResourceConfig, os.Stdout)
} else {
writer.Write(format, results.Violations, os.Stdout)
}
if results.Violations.ViolationStore.Count.TotalCount != 0 {
os.Exit(3)
}
}
5 changes: 4 additions & 1 deletion pkg/cli/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ var (
IacFilePath string
// IacDirPath Path to a directory containing one or more IaC files
IacDirPath string
//ConfigOnly will output resource config (should only be used for debugging purposes)
ConfigOnly bool
)

var scanCmd = &cobra.Command{
Expand All @@ -51,7 +53,7 @@ Detect compliance and security violations across Infrastructure as Code to mitig

func scan(cmd *cobra.Command, args []string) {
zap.S().Debug("running terrascan in cli mode")
Run(IacType, IacVersion, PolicyType, IacFilePath, IacDirPath, ConfigFile, PolicyPath, OutputType)
Run(IacType, IacVersion, PolicyType, IacFilePath, IacDirPath, ConfigFile, PolicyPath, OutputType, ConfigOnly)
}

func init() {
Expand All @@ -61,6 +63,7 @@ func init() {
scanCmd.Flags().StringVarP(&IacFilePath, "iac-file", "f", "", "path to a single IaC file")
scanCmd.Flags().StringVarP(&IacDirPath, "iac-dir", "d", ".", "path to a directory containing one or more IaC files")
scanCmd.Flags().StringVarP(&PolicyPath, "policy-path", "p", "", "policy path directory")
scanCmd.Flags().BoolVarP(&ConfigOnly, "config-only", "", false, "will output resource config (should only be used for debugging purposes)")
scanCmd.MarkFlagRequired("policy-type")
RegisterCommand(rootCmd, scanCmd)
}
10 changes: 4 additions & 6 deletions pkg/runtime/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"go.uber.org/zap"

iacProvider "github.com/accurics/terrascan/pkg/iac-providers"
"github.com/accurics/terrascan/pkg/iac-providers/output"
"github.com/accurics/terrascan/pkg/notifications"
"github.com/accurics/terrascan/pkg/policy"
opa "github.com/accurics/terrascan/pkg/policy/opa"
Expand Down Expand Up @@ -95,21 +94,20 @@ func (e *Executor) Init() error {
}

// Execute validates the inputs, processes the IaC, creates json output
func (e *Executor) Execute() (results policy.EngineOutput, err error) {
func (e *Executor) Execute() (results Output, err error) {

// create results output from Iac
var normalized output.AllResourceConfigs
if e.filePath != "" {
normalized, err = e.iacProvider.LoadIacFile(e.filePath)
results.ResourceConfig, err = e.iacProvider.LoadIacFile(e.filePath)
} else {
normalized, err = e.iacProvider.LoadIacDir(e.dirPath)
results.ResourceConfig, err = e.iacProvider.LoadIacDir(e.dirPath)
}
if err != nil {
return results, err
}

// evaluate policies
results, err = e.policyEngine.Evaluate(policy.EngineInput{InputData: &normalized})
results.Violations, err = e.policyEngine.Evaluate(policy.EngineInput{InputData: &results.ResourceConfig})
if err != nil {
return results, err
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/runtime/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
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 runtime

import (
"github.com/accurics/terrascan/pkg/iac-providers/output"
"github.com/accurics/terrascan/pkg/policy"
)

// Output is the runtime engine output
type Output struct {
ResourceConfig output.AllResourceConfigs
Violations policy.EngineOutput
}
4 changes: 1 addition & 3 deletions pkg/writer/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ package writer
import (
"encoding/json"
"io"

"github.com/accurics/terrascan/pkg/policy"
)

const (
Expand All @@ -32,7 +30,7 @@ func init() {
}

// JSONWriter prints data in JSON format
func JSONWriter(data policy.EngineOutput, writer io.Writer) error {
func JSONWriter(data interface{}, writer io.Writer) error {
j, _ := json.MarshalIndent(data, "", " ")
writer.Write(j)
writer.Write([]byte{'\n'})
Expand Down
6 changes: 2 additions & 4 deletions pkg/writer/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@ package writer

import (
"io"

"github.com/accurics/terrascan/pkg/policy"
)

// supportedFormat data type for supported formats
type supportedFormat string

// writerMap stores mapping of supported writer formats with respective functions
var writerMap = make(map[supportedFormat](func(policy.EngineOutput, io.Writer) error))
var writerMap = make(map[supportedFormat](func(interface{}, io.Writer) error))

// RegisterWriter registers a writer for terrascan
func RegisterWriter(format supportedFormat, writerFunc func(policy.EngineOutput, io.Writer) error) {
func RegisterWriter(format supportedFormat, writerFunc func(interface{}, io.Writer) error) {
writerMap[format] = writerFunc
}
3 changes: 1 addition & 2 deletions pkg/writer/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"fmt"
"io"

"github.com/accurics/terrascan/pkg/policy"
"go.uber.org/zap"
)

Expand All @@ -29,7 +28,7 @@ var (
)

// Write method writes in the given format using the respective writer func
func Write(format string, data policy.EngineOutput, writer io.Writer) error {
func Write(format string, data interface{}, writer io.Writer) error {

writerFunc, present := writerMap[supportedFormat(format)]
if !present {
Expand Down
3 changes: 1 addition & 2 deletions pkg/writer/xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"encoding/xml"
"io"

"github.com/accurics/terrascan/pkg/policy"
"go.uber.org/zap"
)

Expand All @@ -33,7 +32,7 @@ func init() {
}

// XMLWriter prints data in XML format
func XMLWriter(data policy.EngineOutput, writer io.Writer) error {
func XMLWriter(data interface{}, writer io.Writer) error {
j, err := xml.MarshalIndent(data, "", " ")
if err != nil {
zap.S().Errorf("failed to write XML output. error: '%v'", err)
Expand Down
3 changes: 1 addition & 2 deletions pkg/writer/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package writer
import (
"io"

"github.com/accurics/terrascan/pkg/policy"
"gopkg.in/yaml.v2"
)

Expand All @@ -32,7 +31,7 @@ func init() {
}

// YAMLWriter prints data in YAML format
func YAMLWriter(data policy.EngineOutput, writer io.Writer) error {
func YAMLWriter(data interface{}, writer io.Writer) error {
j, _ := yaml.Marshal(data)
writer.Write(j)
writer.Write([]byte{'\n'})
Expand Down

0 comments on commit 618475a

Please sign in to comment.