Skip to content

Commit

Permalink
feat(client/server): add --token-headers option (aquasecurity#326)
Browse files Browse the repository at this point in the history
* feat(option): add token-header

* feat(client): add token header

* feat(server): add token header

* test(token): fix tests

* test(token): add integration tests

* feat(client): add --custom-headers
  • Loading branch information
knqyf263 authored Dec 24, 2019
1 parent b127c1c commit 823374b
Show file tree
Hide file tree
Showing 18 changed files with 281 additions and 192 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI
- [Client/Server](#client--server)
- [Server](#server)
- [Client](#client)
- [Authentication](#authentication)
- [Continuous Integration (CI)](#continuous-integration-ci)
- [Travis CI](#travis-ci)
- [CircleCI](#circleci)
Expand Down Expand Up @@ -1126,6 +1127,15 @@ Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 0, CRITICAL: 0)
```
</details>

### Authentication

```
$ trivy server --listen localhost:8080 --token dummy
```

```
$ trivy client --remote http://localhost:8080 --token dummy alpine:3.10
```

### Deprecated options

Expand Down
60 changes: 39 additions & 21 deletions integration/client_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import (

func TestClientServer(t *testing.T) {
type args struct {
Version string
IgnoreUnfixed bool
Severity []string
IgnoreIDs []string
Input string
ClientToken string
ServerToken string
Version string
IgnoreUnfixed bool
Severity []string
IgnoreIDs []string
Input string
ClientToken string
ClientTokenHeader string
ServerToken string
ServerTokenHeader string
}
cases := []struct {
name string
Expand All @@ -45,10 +47,12 @@ func TestClientServer(t *testing.T) {
{
name: "alpine 3.10 integration with token",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/alpine-310.tar.gz",
ClientToken: "token",
ServerToken: "token",
Version: "dev",
Input: "testdata/fixtures/alpine-310.tar.gz",
ClientToken: "token",
ClientTokenHeader: "Trivy-Token",
ServerToken: "token",
ServerTokenHeader: "Trivy-Token",
},
golden: "testdata/alpine-310.json.golden",
},
Expand Down Expand Up @@ -276,10 +280,24 @@ func TestClientServer(t *testing.T) {
{
name: "invalid token",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "invalidtoken",
ServerToken: "token",
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "invalidtoken",
ClientTokenHeader: "Trivy-Token",
ServerToken: "token",
ServerTokenHeader: "Trivy-Token",
},
wantErr: "twirp error unauthenticated: invalid token",
},
{
name: "invalid token header",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/distroless-base.tar.gz",
ClientToken: "valid-token",
ClientTokenHeader: "Trivy-Token",
ServerToken: "valid-token",
ServerTokenHeader: "Invalid",
},
wantErr: "twirp error unauthenticated: invalid token",
},
Expand All @@ -299,7 +317,7 @@ func TestClientServer(t *testing.T) {
// Setup CLI App
app := internal.NewApp(c.testArgs.Version)
app.Writer = ioutil.Discard
osArgs := setupServer(addr, c.testArgs.ServerToken, cacheDir)
osArgs := setupServer(addr, c.testArgs.ServerToken, c.testArgs.ServerTokenHeader, cacheDir)

// Run Trivy server
require.NoError(t, app.Run(osArgs), c.name)
Expand All @@ -313,7 +331,7 @@ func TestClientServer(t *testing.T) {
app.Writer = ioutil.Discard

osArgs, outputFile, cleanup := setupClient(t, c.testArgs.IgnoreUnfixed, c.testArgs.Severity,
c.testArgs.IgnoreIDs, addr, c.testArgs.ClientToken, c.testArgs.Input, cacheDir, c.golden)
c.testArgs.IgnoreIDs, addr, c.testArgs.ClientToken, c.testArgs.ClientTokenHeader, c.testArgs.Input, cacheDir, c.golden)
defer cleanup()

// Run Trivy client
Expand All @@ -338,16 +356,16 @@ func TestClientServer(t *testing.T) {
}
}

func setupServer(addr, token, cacheDir string) []string {
func setupServer(addr, token, tokenHeader, cacheDir string) []string {
osArgs := []string{"trivy", "server", "--skip-update", "--cache-dir", cacheDir, "--listen", addr}
if token != "" {
osArgs = append(osArgs, []string{"--token", token}...)
osArgs = append(osArgs, []string{"--token", token, "--token-header", tokenHeader}...)
}
return osArgs
}

func setupClient(t *testing.T, ignoreUnfixed bool, severity, ignoreIDs []string,
addr, token, input, cacheDir, golden string) ([]string, string, func()) {
addr, token, tokenHeader, input, cacheDir, golden string) ([]string, string, func()) {
t.Helper()
osArgs := []string{"trivy", "client", "--cache-dir", cacheDir,
"--format", "json", "--remote", "http://" + addr}
Expand All @@ -371,7 +389,7 @@ func setupClient(t *testing.T, ignoreUnfixed bool, severity, ignoreIDs []string,
osArgs = append(osArgs, []string{"--ignorefile", trivyIgnore}...)
}
if token != "" {
osArgs = append(osArgs, []string{"--token", token}...)
osArgs = append(osArgs, []string{"--token", token, "--token-header", tokenHeader}...)
}
if input != "" {
osArgs = append(osArgs, []string{"--input", input}...)
Expand Down
23 changes: 18 additions & 5 deletions internal/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import (
"strings"
"time"

"github.com/urfave/cli"

"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/internal/client"
"github.com/aquasecurity/trivy/internal/server"

"github.com/aquasecurity/trivy/internal/standalone"
"github.com/aquasecurity/trivy/pkg/vulnerability"

"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/utils"
"github.com/urfave/cli"
"github.com/aquasecurity/trivy/pkg/vulnerability"
)

var (
Expand Down Expand Up @@ -144,6 +143,13 @@ var (
Usage: "for authentication",
EnvVar: "TRIVY_TOKEN",
}

tokenHeader = cli.StringFlag{
Name: "token-header",
Value: "Trivy-Token",
Usage: "specify a header name for token",
EnvVar: "TRIVY_TOKEN_HEADER",
}
)

func NewApp(version string) *cli.App {
Expand Down Expand Up @@ -243,12 +249,18 @@ func NewClientCommand() cli.Command {

// original flags
token,
tokenHeader,
cli.StringFlag{
Name: "remote",
Value: "http://localhost:4954",
Usage: "server address",
EnvVar: "TRIVY_REMOTE",
},
cli.StringSliceFlag{
Name: "custom-headers",
Usage: "custom headers",
EnvVar: "TRIVY_CUSTOM_HEADERS",
},
},
}
}
Expand All @@ -269,6 +281,7 @@ func NewServerCommand() cli.Command {

// original flags
token,
tokenHeader,
cli.StringFlag{
Name: "listen",
Value: "localhost:4954",
Expand Down
33 changes: 29 additions & 4 deletions internal/client/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"net/http"
"os"
"strings"
"time"
Expand Down Expand Up @@ -36,8 +37,11 @@ type Config struct {
IgnoreUnfixed bool
ExitCode int

RemoteAddr string
Token string
RemoteAddr string
token string
tokenHeader string
customHeaders []string
CustomHeaders http.Header

// these variables are generated by Init()
ImageName string
Expand Down Expand Up @@ -76,15 +80,23 @@ func New(c *cli.Context) (Config, error) {
IgnoreUnfixed: c.Bool("ignore-unfixed"),
ExitCode: c.Int("exit-code"),

RemoteAddr: c.String("remote"),
Token: c.String("token"),
RemoteAddr: c.String("remote"),
token: c.String("token"),
tokenHeader: c.String("token-header"),
customHeaders: c.StringSlice("custom-headers"),
}, nil
}

func (c *Config) Init() (err error) {
c.Severities = c.splitSeverity(c.severities)
c.VulnType = strings.Split(c.vulnType, ",")
c.AppVersion = c.context.App.Version
c.CustomHeaders = splitCustomHeaders(c.customHeaders)

// add token to custom headers
if c.token != "" {
c.CustomHeaders.Set(c.tokenHeader, c.token)
}

// --clear-cache doesn't conduct the scan
if c.ClearCache {
Expand Down Expand Up @@ -135,3 +147,16 @@ func (c *Config) splitSeverity(severity string) []dbTypes.Severity {
}
return severities
}

func splitCustomHeaders(headers []string) http.Header {
result := make(http.Header)
for _, header := range headers {
// e.g. x-api-token:XXX
s := strings.SplitN(header, ":", 2)
if len(s) != 2 {
continue
}
result.Set(s[0], s[1])
}
return result
}
Loading

0 comments on commit 823374b

Please sign in to comment.