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

config file changes for terrascan server #780

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 pkg/cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Run Terrascan as an API server that inspects incoming IaC (Infrastructure-as-Cod
}

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

func init() {
Expand Down
32 changes: 32 additions & 0 deletions pkg/config/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ var (
// in configFile will get default values
func LoadGlobalConfig(configFile string) error {
// Start with the defaults
global = &TerrascanConfig{}

global.Policy = Policy{
BasePath: defaultBasePolicyPath,
RepoPath: defaultPolicyRepoPath,
Expand Down Expand Up @@ -120,50 +122,80 @@ func LoadGlobalConfig(configFile string) error {

// GetPolicyBasePath returns the configured policy base path
func GetPolicyBasePath() string {
if global == nil {
kanchwala-yusuf marked this conversation as resolved.
Show resolved Hide resolved
return defaultBasePolicyPath
}
return global.Policy.BasePath
}

// GetPolicyRepoPath return the configured path to the policies repo locally downloaded
func GetPolicyRepoPath() string {
if global == nil {
return defaultPolicyRepoPath
}
return global.Policy.RepoPath
}

// GetPolicyRepoURL returns the configured policy repo url
func GetPolicyRepoURL() string {
if global == nil {
return defaultPolicyRepoURL
}
return global.Policy.RepoURL
}

// GetPolicyBranch returns the configured policy repo url
func GetPolicyBranch() string {
if global == nil {
return defaultPolicyBranch
}
return global.Policy.Branch
}

// GetScanRules returns the configured scan rules
func GetScanRules() []string {
if global == nil {
return nil
}
return global.Rules.ScanRules
}

// GetSkipRules returns the configured skips rules
func GetSkipRules() []string {
if global == nil {
return nil
}
return global.Rules.SkipRules
}

// GetSeverityLevel returns the configured severity level
func GetSeverityLevel() string {
if global == nil {
return ""
}
return global.Severity.Level
}

// GetCategoryList returns the configured list of category of violations
func GetCategoryList() []string {
if global == nil {
return nil
}
return global.Category.List
}

// GetNotifications returns the configured notifier map
func GetNotifications() map[string]Notifier {
if global == nil {
return nil
}
return global.Notifications
}

// GetK8sAdmissionControl returns kubernetes admission control configuration
func GetK8sAdmissionControl() K8sAdmissionControl {
if global == nil {
return K8sAdmissionControl{}
}
return global.K8sAdmissionControl
}
2 changes: 1 addition & 1 deletion pkg/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package config

// Global initalizes GlobalConfig struct
var global *TerrascanConfig = &TerrascanConfig{}
var global *TerrascanConfig

// TerrascanConfig struct defines global variables/configurations across terrascan
type TerrascanConfig struct {
Expand Down
9 changes: 3 additions & 6 deletions pkg/http-server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ package httpserver

// APIHandler struct for http api server
type APIHandler struct {
test bool
configFile string
test bool
}

// NewAPIHandler returns a new APIHandler{}
func NewAPIHandler(configFile string) *APIHandler {
return &APIHandler{
configFile: configFile,
}
func NewAPIHandler() *APIHandler {
return &APIHandler{}
}
6 changes: 2 additions & 4 deletions pkg/http-server/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import (
func TestNewAPIHandler(t *testing.T) {
t.Run("new API gateway", func(t *testing.T) {
var (
want = APIHandler{
configFile: "",
}
got = NewAPIHandler("")
want = APIHandler{}
got = NewAPIHandler()
)
if !reflect.DeepEqual(*got, want) {
t.Errorf("got: '%v', want: '%v'", *got, want)
Expand Down
2 changes: 1 addition & 1 deletion pkg/http-server/health_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

func TestHealth(t *testing.T) {

handler := NewAPIHandler("")
handler := NewAPIHandler()

t.Run("test health api", func(t *testing.T) {
var (
Expand Down
2 changes: 2 additions & 0 deletions pkg/http-server/k8s_testdata/config-dashboard-true.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[k8s-admission-control]
dashboard = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[k8s-admission-control]
dashboard = true
denied-categories = [
"Identity and Access Management",
"Network Security",
]
4 changes: 2 additions & 2 deletions pkg/http-server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ type Route struct {

// Routes returns a slice of routes of API endpoints to be registered with
// http server
func (g *APIServer) Routes(configFile string) []*Route {
h := NewAPIHandler(configFile)
func (g *APIServer) Routes() []*Route {
h := NewAPIHandler()
routes := []*Route{
{verb: "GET", path: "/health", fn: h.Health},
{verb: "POST", path: versionedPath("/{iac}/{iacVersion}/{cloud}/local/file/scan"), fn: h.scanFile},
Expand Down
2 changes: 1 addition & 1 deletion pkg/http-server/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func TestRoutes(t *testing.T) {
t.Run("health route check", func(t *testing.T) {
var (
server = NewAPIServer()
got = server.Routes("")
got = server.Routes()
passed = false
)

Expand Down
4 changes: 2 additions & 2 deletions pkg/http-server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ import (
)

// Start initializes api routes and starts http server
func Start(port, configFile, certFile, privateKeyFile string) {
func Start(port, certFile, privateKeyFile string) {

// create a new API server
server := NewAPIServer()

// get all routes
routes := server.Routes(configFile)
routes := server.Routes()

// get port
if port == GatewayDefaultPort && os.Getenv(TerrascanServerPort) != "" {
Expand Down
2 changes: 1 addition & 1 deletion pkg/http-server/webhook-scan-logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) {
)

// Validate if authorized (API key is specified and matched the server one (saved in an environment variable)
validatingWebhook := admissionWebhook.NewValidatingWebhook(g.configFile, []byte(""))
validatingWebhook := admissionWebhook.NewValidatingWebhook([]byte(""))
if err := validatingWebhook.Authorize(apiKey); err != nil {
switch err {
case admissionWebhook.ErrAPIKeyMissing:
Expand Down
2 changes: 1 addition & 1 deletion pkg/http-server/webhook-scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (g *APIHandler) validateK8SWebhook(w http.ResponseWriter, r *http.Request)
}
zap.S().Debugf("scanning configuration webhook request: %+v", string(body))

validatingWebhook := admissionWebhook.NewValidatingWebhook(g.configFile, body)
validatingWebhook := admissionWebhook.NewValidatingWebhook(body)
// Validate if authorized (API key is specified and matched the server one (saved in an environment variable)
if err := validatingWebhook.Authorize(apiKey); err != nil {
switch err {
Expand Down
50 changes: 35 additions & 15 deletions pkg/http-server/webhook-scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"

"github.com/accurics/terrascan/pkg/config"
"github.com/accurics/terrascan/pkg/k8s/dblogs"
"github.com/gorilla/mux"
v1 "k8s.io/api/admission/v1"
Expand All @@ -34,6 +36,7 @@ func TestUWebhooks(t *testing.T) {
allowed bool
statusCode int32
statusMessage bool
dashboardCheck bool
}{
{
name: "missing api key",
Expand All @@ -59,14 +62,6 @@ func TestUWebhooks(t *testing.T) {
wantStatus: http.StatusUnauthorized,
configFile: testConfigFile,
},
{
name: "invalid api key",
contentRequestPath: testFilePath,
apiKey: testAPIKey,
envAPIKey: "Invalid API KEY",
wantStatus: http.StatusUnauthorized,
configFile: testConfigFile,
},
{
name: "invalid request json content",
contentRequestPath: filepath.Join(k8sTestData, "invalid.json"),
Expand Down Expand Up @@ -167,10 +162,39 @@ func TestUWebhooks(t *testing.T) {
allowed: true,
wantStatus: http.StatusOK,
},
{
name: "risky request object with dashboard true",
contentRequestPath: filepath.Join(k8sTestData, "risky_testconfig.json"),
apiKey: testAPIKey,
envAPIKey: testEnvAPIKey,
configFile: filepath.Join(k8sTestData, "config-dashboard-true.toml"),
warnings: true,
allowed: true,
wantStatus: http.StatusOK,
dashboardCheck: true,
},
{
name: "risky request object with denied categories and dashboard true",
contentRequestPath: filepath.Join(k8sTestData, "risky_testconfig.json"),
apiKey: testAPIKey,
envAPIKey: testEnvAPIKey,
configFile: filepath.Join(k8sTestData, "config-with-dashboard-deny-categories.toml"),
warnings: false,
allowed: false,
statusCode: 403,
statusMessage: true,
wantStatus: http.StatusOK,
dashboardCheck: true,
},
}

for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
err := config.LoadGlobalConfig(tt.configFile)
if err != nil {
t.Errorf("error while loading the config file '%s', error: %v", tt.configFile, err)
}

os.Setenv("K8S_WEBHOOK_API_KEY", tt.envAPIKey)

// test file to upload
Expand Down Expand Up @@ -206,7 +230,7 @@ func TestUWebhooks(t *testing.T) {
})
res := httptest.NewRecorder()
// new api handler
h := &APIHandler{test: true, configFile: tt.configFile}
h := &APIHandler{test: true}
h.validateK8SWebhook(res, req)

if res.Code != tt.wantStatus {
Expand All @@ -229,11 +253,7 @@ func TestUWebhooks(t *testing.T) {
t.Errorf("mismatch Status code Got: %v, expected: %v", response.Response.Result.Code, tt.statusCode)
}

// TODO: this needs to improved and more tests added after the config file changes
// commenting the log message check for now, it can be fixed later
// making the blind mode default has changed the log message output

/*
if tt.dashboardCheck {
if tt.warnings || tt.statusMessage {
var logPath string
if tt.warnings {
Expand All @@ -249,7 +269,7 @@ func TestUWebhooks(t *testing.T) {
t.Errorf("mismatch Log path. Got: %v, expected: %v", logPath, expectedLogPath)
}
}
*/
}
}
})
}
Expand Down
14 changes: 3 additions & 11 deletions pkg/k8s/admission-webhook/validating-webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,13 @@ import (
// the kubernetes API server and decides whether the admission request from
// the kubernetes client should be allowed or not
type ValidatingWebhook struct {
configFile string
requestBody []byte
dblogger *dblogs.WebhookScanLogger
}

// NewValidatingWebhook returns a new, empty ValidatingWebhook struct
func NewValidatingWebhook(configFile string, body []byte) AdmissionWebhook {
func NewValidatingWebhook(body []byte) AdmissionWebhook {
return ValidatingWebhook{
configFile: configFile,
dblogger: dblogs.NewWebhookScanLogger(),
requestBody: body,
}
Expand Down Expand Up @@ -162,7 +160,7 @@ func (w ValidatingWebhook) ProcessWebhook(review admissionv1.AdmissionReview, se
return w.createResponseAdmissionReview(review, allowed, output, logMsg), fmt.Errorf(errMsg, msg, err)
}

// Calculate if there are anydeny violations
// Calculate if there are any deny violations
denyViolations, err = w.getDenyViolations(output)
if err != nil {
msg := "failed to figure out denied violations"
Expand Down Expand Up @@ -215,13 +213,7 @@ func (w ValidatingWebhook) scanK8sFile(filePath string) (runtime.Output, error)
func (w ValidatingWebhook) getDenyViolations(output runtime.Output) ([]results.Violation, error) {

// Calcualte the deny violations according to the configuration specified in the config file
configReader, err := config.NewTerrascanConfigReader(w.configFile)
if err != nil {
zap.S().Errorf("error loading config file: '%v'", err)
return nil, err
}

denyViolations := w.getDeniedViolations(*output.Violations.ViolationStore, configReader.GetK8sAdmissionControl())
denyViolations := w.getDeniedViolations(*output.Violations.ViolationStore, config.GetK8sAdmissionControl())

return denyViolations, nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/notifications/notifiers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestNewNotifiers(t *testing.T) {
},
{
name: "no config file specified",
wantErr: nil,
wantErr: ErrNotificationNotPresent,
},
}

Expand Down