Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for validating admission webhook in terrascan #620

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7c2c870
add support for k8s validating webhooks
Mar 12, 2021
fa10ba9
add cert and key file paths flags in server command
Mar 14, 2021
a5b4e5c
add support to accept API server port from user
Mar 14, 2021
0ecddb2
update API path for validating webhook
Mar 14, 2021
eae0b64
fix goimports for k8s webhook files
Mar 14, 2021
8df7693
add support for reading port from env variable
Mar 14, 2021
3a24795
refactor to move k8s specific methods into a dedicated package
Mar 14, 2021
ad8f796
remove API key from webhook logs url
Mar 14, 2021
1d5e6bc
use AdmissionWebhook interface
Mar 14, 2021
c91a31c
override default server port with port from env variable
Mar 15, 2021
814b623
fixing typos, handling pointers, refactoring some code
Mar 15, 2021
fc640ec
fixing unit tests
Mar 15, 2021
4292f1e
fixing linter issues
Mar 15, 2021
a2f211a
fixing go import issues
Mar 15, 2021
ebcba45
fix staticheck errors
Mar 15, 2021
e487102
removing redundant repos
Mar 15, 2021
6aceaa7
removing unnecessary file changes
Mar 16, 2021
e8f9dac
fixing html file for fetching all logs
Mar 18, 2021
bfb84a2
adding some unit tests
Mar 19, 2021
be2255f
refactor to move db logger into a separate dedicated package
Mar 19, 2021
66fc76e
refactor validate handler to move specific functionality into webhook…
Mar 20, 2021
6a1cbef
making staticcheck happy
Mar 20, 2021
0f67bb1
improve error message send as part of kubernetes admission response
Mar 22, 2021
09e55dc
fixing unit tests for http server
Mar 30, 2021
ffad7ad
go mod tidy
Mar 31, 2021
ef75299
adding review comments
Apr 1, 2021
6863010
sonar linter fixes
Apr 1, 2021
bdb11b5
fixing code smells and bugs in UI
Apr 2, 2021
5bb303c
trying to make sonar lint happy
Apr 2, 2021
90b8429
fixing html file bugs
Apr 3, 2021
056a9f2
Update docs/getting-started/admission-controller-webhooks-usage.md
kanchwala-yusuf Apr 5, 2021
0ef2a8d
Update pkg/http-server/start.go
kanchwala-yusuf Apr 5, 2021
e405999
fixing documentation bullets
Apr 6, 2021
d9e2a71
updating documentation
Apr 6, 2021
f31634c
fix: admission request is saved in db logs
Apr 7, 2021
a53ce45
fixing go mod files
Apr 7, 2021
8d82d90
serving the CSS locally instead of fetching from internet
Apr 8, 2021
1911323
accommodating review comments on documentation
Apr 8, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ docs/_build/

.DS_Store

vendor/
vendor/
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null)
BUILD_FLAGS := -v -ldflags "-w -s"
ENV_SETTINGS := CGO_ENABLED=0
ENV_SETTINGS := CGO_ENABLED=1

BUILD_DIR = ./bin
BINARY_NAME = terrascan
Expand Down
7 changes: 6 additions & 1 deletion build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ FROM golang:alpine AS builder

ARG GOOS_VAL=linux
ARG GOARCH_VAL=amd64
ARG CGO_ENABLED_VAL=0
ARG CGO_ENABLED_VAL=1

WORKDIR $GOPATH/src/terrascan

# download go dependencies
COPY go.mod go.sum ./
RUN go mod download
RUN apk add -U build-base

# copy terrascan source
COPY . .
Expand All @@ -34,6 +35,10 @@ ENV PATH /go/bin:$PATH
# copy terrascan binary from build
COPY --from=builder /go/bin/terrascan /go/bin/terrascan

# Copy webhooks UI templates & assets
COPY ./pkg/http-server/templates /go/terrascan
COPY ./pkg/http-server/assets /go/terrascan/assets

EXPOSE 9010

ENTRYPOINT ["/go/bin/terrascan"]
Expand Down
104 changes: 104 additions & 0 deletions docs/getting-started/admission-controller-webhooks-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Using Terrascan as a Kubernetes Admission Controller

## Overview
Terrascan can be integrated with K8s [admissions webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/).
It can be used as one of the validating webhooks to be used and scan new configurations.

In this guide, we'll demonstrate how Terrascan can be configured to:
* Scan configuration changes policies when an object is being created or updated
* Allow / reject the request in case a violation is detected


## Installation Guide

### Create an instance
Your Terrascan instance has the following requirements for being able to scan K8s configurations.

1. Be accessible via HTTPS. Make sure your cloud firewall is configured to allow this.
kanchwala-yusuf marked this conversation as resolved.
Show resolved Hide resolved
2. Have a valid SSL certificate for the served domain name. To do that, choose one of our suggested methods:
- Use a subdomain of your choosing (e.g dev-terrascan-k8s.accurics.com) and create a valid certificate for this subdomain through your SSL certificate provider. [Let's Encrypt](https://letsencrypt.org/) is a free, simple to use certificate authority you can use.
- Use a reverse-proxy to serve SSL requests; for example, use Cloudflare Flexible to get a certificate by a trusted-CA to your [self-signed certificate](https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs).
- Generate a self-signed certificate and have your K8s cluster trust it. To add a trusted CA to ca-pemstore, as demonstrated in [paraspatidar's blog post](https://medium.com/@paraspatidar/add-ssl-tls-certificate-or-pem-file-to-kubernetes-pod-s-trusted-root-ca-store-7bed5cd683d).
3. Use the Terrascan docker as demonstrated in this document, or run it from the sources.

### Run Terrascan webhook service
Run Terrascan docker image in your server using the following command:
```bash
sudo docker run -p 443:9443 -v <DATA_PATH>:/data -u root -e K8S_WEBHOOK_API_KEY=<API_KEY> accurics/terrascan server --cert-path /data/cert.pem --key-path /data/key.pem -c /data/config.toml
```
`<API_KEY>` is a key used for authentication between your K8s environment and the Terrascan server. Generate your preferred key and use it here.

`<DATA_PATH>` is a directory path in your server where both the certificate and the private key .pem files are stored.
In addition, this directory is used to save the webhook logs. (An SQLite file)

You can specify a config file that specifies which policies to use in the scan and which violations should lead to rejection.

A config file example: ```config.toml```
```bash
[severity]
level = "medium"
[rules]
skip-rules = [
"accurics.kubernetes.IAM.107"
]

[k8s-deny-rules]
denied-categories = [
"Network Ports Security"
]
denied-severity = "high"
```

You can specify the following configurations:
* **scan-rules** - one or more rules to scan
* **skip-rules** - one or more rules to skip while scanning
* **severity** - the minimal level of severity of the policies to be scanned
* **category** - the list of type of categories of the policies to be scanned

kanchwala-yusuf marked this conversation as resolved.
Show resolved Hide resolved

* **k8s-deny-rules** - specify the rules that should cause a rejection of the admission request
* **denied-categories** - one or more policy categories that are not allowed in the detected violations
* **denied-severity** - the minimal level of severity that should cause a rejection

### Configure K8s to send webhooks
Configure a new ```ValidatingWebhookConfiguration``` in your Kubernetes environment and specify your Terrascan server endpoint.

Example:
```bash
cat <<EOF | kubectl apply -f -
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: my.validation.example.check
webhooks:
- name: my.validation.example.check
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
- services
failurePolicy: Fail
clientConfig:
url: https://<SERVER_ADDRESS>/v1/k8s/webhooks/<API_KEY>/scan
sideEffects: None
admissionReviewVersions: ["v1"]
EOF
```

* You can modify the `rules` that trigger the webhook according to your preferences.
* Update the ```clientConfig``` URL with your terrascan server address and the API key you generated before.


### Test your settings
Try to run a new pod / service. For example:
``` Bash
kubectl run mynginx --image=nginx
```

Go to ```https://<SERVER_ADDRESS>/k8s/webhooks/<API_KEY>/logs``` and verify your request is logged.
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/iancoleman/strcase v0.1.3
github.com/itchyny/gojq v0.12.1
github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-sqlite3 v1.12.0
github.com/mitchellh/go-homedir v1.1.0
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.5
Expand All @@ -31,11 +32,12 @@ require (
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-20210324051608-47abb6519492
golang.org/x/tools v0.1.0 // indirect
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4
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
k8s.io/api v0.19.2
k8s.io/apimachinery v0.19.2
sigs.k8s.io/kustomize/api v0.8.5
)
9 changes: 7 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,9 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down Expand Up @@ -578,6 +580,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
Expand Down Expand Up @@ -632,6 +635,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.12.0 h1:u/x3mp++qUxvYfulZ4HKOvVO0JWhk7HtE8lWhbGz/Do=
github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
Expand Down Expand Up @@ -853,6 +857,7 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand Down Expand Up @@ -941,6 +946,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
Expand Down Expand Up @@ -1129,8 +1135,6 @@ golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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=
Expand Down Expand Up @@ -1309,6 +1313,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
Expand Down
3 changes: 3 additions & 0 deletions pkg/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ import (
var (
// LogLevel Logging level (debug, info, warn, error, panic, fatal)
LogLevel string

// LogType Logging output type (console, json)
LogType string

// OutputType Violation output type (human, json, yaml, xml)
OutputType string

// ConfigFile Config file path
ConfigFile string
)
Expand Down
16 changes: 15 additions & 1 deletion pkg/cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ import (
"github.com/spf13/cobra"
)

var (
// Port at which API server will listen
port string

// CertFile Certificate file path, required in order to enable secure HTTP server
certFile string

// PrivateKeyFile Private key file path, required in order to enable secure HTTP server
privateKeyFile string
)

var serverCmd = &cobra.Command{
Use: "server",
Short: "Run Terrascan as an API server",
Expand All @@ -35,9 +46,12 @@ Run Terrascan as an API server that inspects incoming IaC (Infrastructure-as-Cod
}

func server(cmd *cobra.Command, args []string) {
httpserver.Start()
httpserver.Start(port, ConfigFile, certFile, privateKeyFile)
}

func init() {
serverCmd.Flags().StringVarP(&privateKeyFile, "key-path", "", "", "private key file path")
serverCmd.Flags().StringVarP(&certFile, "cert-path", "", "", "certificate file path")
serverCmd.Flags().StringVarP(&port, "port", "p", httpserver.GatewayDefaultPort, "server port")
RegisterCommand(rootCmd, serverCmd)
}
5 changes: 5 additions & 0 deletions pkg/config/config-reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,8 @@ func (r TerrascanConfigReader) getCategory() Category {
func (r TerrascanConfigReader) getSeverity() Severity {
return r.config.Severity
}

// GetK8sDenyRules will return the k8s deny rules specified in the terrascan config file
func (r TerrascanConfigReader) GetK8sDenyRules() K8sDenyRules {
return r.config.K8sDenyRules
}
7 changes: 7 additions & 0 deletions pkg/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type TerrascanConfig struct {
Rules `toml:"rules,omitempty"`
Category `toml:"category,omitempty"`
Severity `toml:"severity,omitempty"`
K8sDenyRules `toml:"k8s-deny-rules,omitempty"`
}

// Category defines the categories of violations that you want to be reported
Expand Down Expand Up @@ -61,3 +62,9 @@ type Rules struct {
ScanRules []string `toml:"scan-rules,omitempty"`
SkipRules []string `toml:"skip-rules,omitempty"`
}

// K8sDenyRules deny rules in the terrascan config file
type K8sDenyRules struct {
DeniedSeverity string `toml:"denied-severity,omitempty"`
Categories []string `toml:"denied-categories,omitempty"`
}
7 changes: 7 additions & 0 deletions pkg/http-server/assets/bootstrap.min.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pkg/http-server/assets/icons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading