Skip to content

Commit

Permalink
Merge branch 'master' of github.com:accurics/terrascan into argo-cd-hook
Browse files Browse the repository at this point in the history
  • Loading branch information
iceal lim committed Jan 12, 2021
2 parents e0e6bd7 + 5c565e6 commit 23fe143
Show file tree
Hide file tree
Showing 22 changed files with 702 additions and 103 deletions.
95 changes: 50 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
[![community](https://img.shields.io/discourse/status?server=https%3A%2F%2Fcommunity.accurics.com)](https://community.accurics.com)
[![Documentation Status](https://readthedocs.com/projects/accurics-terrascan/badge/?version=latest)](https://docs.accurics.com/projects/accurics-terrascan/en/latest/?badge=latest)

Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure.
Detect security vulnerabilities and compliance violations across your Infrastructure as Code. Mitigate risks before provisioning cloud native infrastructure. Run locally or integrate with your CI\CD.


* GitHub Repo: /~https://github.com/accurics/terrascan
* Documentation: https://docs.accurics.com
* Documentation: https://docs.accurics.com/projects/accurics-terrascan
* Discuss: https://community.accurics.com

## Features
Expand All @@ -21,8 +20,11 @@ Detect compliance and security violations across Infrastructure as Code to mitig
* Scanning of Kubernetes (JSON/YAML), Helm v3, and Kustomize v3
* Support for AWS, Azure, GCP, Kubernetes and GitHub

## Installing
Terrascan's binary for your architecture can be found on the [releases](/~https://github.com/accurics/terrascan/releases) page. Here's an example of how to install it:

## Quick Start
### Step 1: Install
Terrascan's supports multiple ways to install, including [brew](/~https://github.com/accurics/terrascan#install-via-brew).
Here, we will download the terrascan binary directly from the [releases](/~https://github.com/accurics/terrascan/releases) page. Make sure to select the right binary for your machine. Here's an example of how to install it:

```sh
$ curl --location /~https://github.com/accurics/terrascan/releases/download/v1.2.0/terrascan_1.2.0_Darwin_x86_64.tar.gz --output terrascan.tar.gz
Expand All @@ -34,44 +36,7 @@ $ tar -xvf terrascan.tar.gz
$ install terrascan /usr/local/bin
$ terrascan
```

If you have go installed, Terrascan can be installed with `go get`
```
$ export GO111MODULE=on
$ go get -u github.com/accurics/terrascan/cmd/terrascan
go: downloading github.com/accurics/terrascan v1.2.0
go: found github.com/accurics/terrascan/cmd/terrascan in github.com/accurics/terrascan v1.2.0
...
$ terrascan
```

### Install via `brew`

[Homebrew](https://brew.sh/) users can install by:

```sh
$ brew install terrascan
```

### Docker
Terrascan is also available as a Docker image and can be used as follows

```sh
$ docker run accurics/terrascan
```

### Building Terrascan
Terrascan can be built locally. This is helpful if you want to be on the latest version or when developing Terrascan.

```sh
$ git clone git@github.com:accurics/terrascan.git
$ cd terrascan
$ make build
$ ./bin/terrascan
```

## Getting started

### Step 2: Run
To scan your code for security issues you can run the following (defaults to scanning Terraform).

```sh
Expand Down Expand Up @@ -109,8 +74,48 @@ Flags:
Use "terrascan [command] --help" for more information about a command.
```

## Documentation
To learn more about Terrascan check out the documentation https://docs.accurics.com where we include a getting started guide, Terrascan's architecture, a breakdown of it's commands, and a deep dive into policies.
### Step 3: Integrate with CI\CD
Please refer to our [documentation to integrate with your pipeline](https://docs.accurics.com/projects/accurics-terrascan/en/latest/cicd/).


## Other Installation Options


### Install via `brew`

[Homebrew](https://brew.sh/) users can install by:

```sh
$ brew install terrascan
```

### Docker
Terrascan is also available as a Docker image and can be used as follows

```sh
$ docker run accurics/terrascan
```

### Install via go get, if you have Go installed
```
$ export GO111MODULE=on
$ go get -u github.com/accurics/terrascan/cmd/terrascan
go: downloading github.com/accurics/terrascan v1.2.0
go: found github.com/accurics/terrascan/cmd/terrascan in github.com/accurics/terrascan v1.2.0
...
$ terrascan
```

### Building Terrascan
Terrascan can be built locally. This is helpful if you want to be on the latest version or when developing Terrascan.

```sh
$ git clone git@github.com:accurics/terrascan.git
$ cd terrascan
$ make build
$ ./bin/terrascan
```


## Developing Terrascan
To learn more about developing and contributing to Terrascan refer to the [contributing guide](CONTRIBUTING.md).
Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mkdocs==1.1.2
mkdocs-material==6.2.3
mkdocs-material==6.2.4
mkdocs-diagrams==1.0.0
9 changes: 6 additions & 3 deletions pkg/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ var initCmd = &cobra.Command{
Initializes Terrascan and clones policies from the Terrascan GitHub repository.
`,
Run: initial,
RunE: initial,
SilenceUsage: true,
SilenceErrors: true,
}

func initial(cmd *cobra.Command, args []string) {
func initial(cmd *cobra.Command, args []string) error {
// initialize terrascan
if err := initialize.Run(); err != nil {
zap.S().Error("failed to initialize terrascan")
return
return err
}
return nil
}

func init() {
Expand Down
24 changes: 0 additions & 24 deletions pkg/cli/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package cli

import (
"flag"
"fmt"
"os"

"github.com/accurics/terrascan/pkg/config"
Expand All @@ -31,27 +30,6 @@ func RegisterCommand(baseCommand *cobra.Command, command *cobra.Command) {
baseCommand.AddCommand(command)
}

func subCommands() (commandNames []string) {
for _, command := range rootCmd.Commands() {
commandNames = append(commandNames, append(command.Aliases, command.Name())...)
}
return
}

// setDefaultCommand sets `scan` as default command if no other command is specified
func setDefaultCommandIfNonePresent() {
if len(os.Args) > 1 {
potentialCommand := os.Args[1]
for _, command := range subCommands() {
if command == potentialCommand {
return
}
}
os.Args = append([]string{os.Args[0], "scan"}, os.Args[1:]...)
}

}

// Execute the entrypoint called by main
func Execute() {
rootCmd.PersistentFlags().StringVarP(&LogLevel, "log-level", "l", "info", "log level (debug, info, warn, error, panic, fatal)")
Expand Down Expand Up @@ -81,9 +59,7 @@ func Execute() {
}
}

setDefaultCommandIfNonePresent()
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
10 changes: 6 additions & 4 deletions pkg/cli/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ var scanCmd = &cobra.Command{
Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure.
`,
PreRun: initial,
Run: scan,
PreRunE: initial,
RunE: scan,
SilenceUsage: true,
SilenceErrors: true,
}

func scan(cmd *cobra.Command, args []string) {
func scan(cmd *cobra.Command, args []string) error {
zap.S().Debug("running terrascan in cli mode")
scanOptions.configFile = ConfigFile
scanOptions.outputType = OutputType
scanOptions.Scan()
return scanOptions.Scan()
}

func init() {
Expand Down
4 changes: 4 additions & 0 deletions pkg/cli/testdata/run-test/test_pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ metadata:
app: myapp
test: someupdate
test2: someupdate3
annotations:
terrascanSkip: [accurics.kubernetes.IAM.109]
spec:
containers:
- name: myapp-container
Expand All @@ -22,6 +24,8 @@ metadata:
app: myapp
test: someupdate
test2: someupdate3
annotations:
terrascanSkip: [accurics.kubernetes.IAM.3, accurics.kubernetes.OPS.461]
spec:
template:
spec:
Expand Down
6 changes: 6 additions & 0 deletions pkg/iac-providers/kubernetes/v1/load-file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ func TestLoadIacFile(t *testing.T) {
k8sV1: K8sV1{},
wantErr: nil,
},
{
name: "file with skip rules in annotations",
filePath: "./testdata/file-test-data/test_pod_skip_rules.yaml",
k8sV1: K8sV1{},
wantErr: nil,
},
}

for _, tt := range table {
Expand Down
41 changes: 38 additions & 3 deletions pkg/iac-providers/kubernetes/v1/normalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ import (
"github.com/accurics/terrascan/pkg/utils"
yamltojson "github.com/ghodss/yaml"
"github.com/iancoleman/strcase"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)

const terrascanSkip = "terrascanSkip"

var (
errUnsupportedDoc = fmt.Errorf("unsupported document type")
// ErrNoKind is returned when the "kind" key is not available (not a valid kubernetes resource)
ErrNoKind = fmt.Errorf("kind does not exist")
)

// k8sMetadata is used to pull the name and namespace types for a given resource
// k8sMetadata is used to pull the name, namespace types and annotations for a given resource
type k8sMetadata struct {
Name string `yaml:"name" json:"name"`
Namespace string `yaml:"namespace" json:"namespace"`
Name string `yaml:"name" json:"name"`
Namespace string `yaml:"namespace" json:"namespace"`
Annotations map[string]interface{} `yaml:"annotations" json:"annotations"`
}

// k8sResource is a generic struct to handle all k8s resource types
Expand Down Expand Up @@ -116,6 +120,12 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error
resourceConfig.ID = resourceConfig.Type + "." + resource.Metadata.Name + "." + namespace
}

// read and update skip rules, if present
skipRules := readSkipRulesFromAnnotations(resource.Metadata.Annotations, resourceConfig.ID)
if skipRules != nil {
resourceConfig.SkipRules = append(resourceConfig.SkipRules, skipRules...)
}

configData := make(map[string]interface{})
if err = json.Unmarshal(*jsonData, &configData); err != nil {
return nil, err
Expand All @@ -126,3 +136,28 @@ func (k *K8sV1) Normalize(doc *utils.IacDocument) (*output.ResourceConfig, error

return &resourceConfig, nil
}

func readSkipRulesFromAnnotations(annotations map[string]interface{}, resourceID string) []string {

var skipRulesFromAnnotations interface{}
var ok bool
if skipRulesFromAnnotations, ok = annotations[terrascanSkip]; !ok {
zap.S().Debugf("%s not present for resource: %s", terrascanSkip, resourceID)
return nil
}

skipRules := make([]string, 0)
if rules, ok := skipRulesFromAnnotations.([]interface{}); ok {
for _, rule := range rules {
if value, ok := rule.(string); ok {
skipRules = append(skipRules, value)
} else {
zap.S().Debugf("each rule in %s must be of string type", terrascanSkip)
}
}
} else {
zap.S().Debugf("%s must be an array of rules to skip", terrascanSkip)
}

return skipRules
}
Loading

0 comments on commit 23fe143

Please sign in to comment.