feat(client): configure TLS InsecureSkipVerify for server connection (#1287)

Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
Christian Zunker
2022-02-13 10:34:34 +01:00
committed by GitHub
parent de6c3cbb6c
commit aa6e1eb6f9
9 changed files with 139 additions and 25 deletions

View File

@@ -19,6 +19,10 @@ linters-settings:
locale: US
goimports:
local-prefixes: github.com/aquasecurity
gosec:
excludes:
- G204
- G402
linters:
disable-all: true
@@ -53,9 +57,6 @@ issues:
- linters:
- gosec
text: "Deferring unsafe method"
- linters:
- gosec
text: "G204: Subprocess launched with variable"
- linters:
- errcheck
text: "Close` is not checked"

17
pkg/cache/remote.go vendored
View File

@@ -2,6 +2,7 @@ package cache
import (
"context"
"crypto/tls"
"net/http"
"golang.org/x/xerrors"
@@ -19,13 +20,19 @@ type RemoteCache struct {
client rpcCache.Cache
}
// RemoteURL to hold remote host
type RemoteURL string
// NewRemoteCache is the factory method for RemoteCache
func NewRemoteCache(url RemoteURL, customHeaders http.Header) cache.ArtifactCache {
func NewRemoteCache(url string, customHeaders http.Header, insecure bool) cache.ArtifactCache {
ctx := client.WithCustomHeaders(context.Background(), customHeaders)
c := rpcCache.NewCacheProtobufClient(string(url), &http.Client{})
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
},
}
c := rpcCache.NewCacheProtobufClient(url, httpClient)
return &RemoteCache{ctx: ctx, client: c}
}

View File

@@ -135,7 +135,7 @@ func TestRemoteCache_PutArtifact(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
@@ -196,7 +196,7 @@ func TestRemoteCache_PutBlob(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
err := c.PutBlob(tt.args.diffID, tt.args.layerInfo)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
@@ -274,7 +274,7 @@ func TestRemoteCache_MissingBlobs(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(cache.RemoteURL(ts.URL), tt.args.customHeaders)
c := cache.NewRemoteCache(ts.URL, tt.args.customHeaders, false)
gotMissingImage, gotMissingLayerIDs, err := c.MissingBlobs(tt.args.imageID, tt.args.layerIDs)
if tt.wantErr != "" {
require.NotNil(t, err, tt.name)
@@ -289,3 +289,49 @@ func TestRemoteCache_MissingBlobs(t *testing.T) {
})
}
}
func TestRemoteCache_PutArtifactInsecure(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
defer ts.Close()
type args struct {
imageID string
imageInfo types.ArtifactInfo
insecure bool
}
tests := []struct {
name string
args args
wantErr string
}{
{
name: "happy path",
args: args{
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
imageInfo: types.ArtifactInfo{},
insecure: true,
},
},
{
name: "sad path",
args: args{
imageID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
imageInfo: types.ArtifactInfo{},
insecure: false,
},
wantErr: "certificate signed by unknown authority",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := cache.NewRemoteCache(ts.URL, nil, tt.args.insecure)
err := c.PutArtifact(tt.args.imageID, tt.args.imageInfo)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
}
assert.NoError(t, err, tt.name)
})
}
}

View File

@@ -309,6 +309,7 @@ var (
insecureFlag = cli.BoolFlag{
Name: "insecure",
Usage: "allow insecure server connections when using SSL",
Value: false,
EnvVars: []string{"TRIVY_INSECURE"},
}
@@ -585,6 +586,7 @@ func NewClientCommand() *cli.Command {
stringSliceFlag(configPolicy),
&listAllPackages,
&offlineScan,
&insecureFlag,
// original flags
&token,

View File

@@ -18,14 +18,14 @@ import (
)
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders,
url client.RemoteURL, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (
url client.RemoteURL, insecure client.Insecure, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (
scanner.Scanner, func(), error) {
wire.Build(scanner.RemoteDockerSet)
return scanner.Scanner{}, nil, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache,
customHeaders client.CustomHeaders, url client.RemoteURL, artifactOption artifact.Option,
customHeaders client.CustomHeaders, url client.RemoteURL, insecure client.Insecure, artifactOption artifact.Option,
configScannerOption config.ScannerOption) (scanner.Scanner, error) {
wire.Build(scanner.RemoteArchiveSet)
return scanner.Scanner{}, nil

View File

@@ -138,7 +138,7 @@ func disabledAnalyzers(opt Option) []analyzer.Type {
}
func initializeScanner(ctx context.Context, opt Option) (scanner.Scanner, func(), error) {
remoteCache := cache.NewRemoteCache(cache.RemoteURL(opt.RemoteAddr), opt.CustomHeaders)
remoteCache := cache.NewRemoteCache(opt.RemoteAddr, opt.CustomHeaders, opt.Insecure)
// ScannerOptions is filled only when config scanning is enabled.
var configScannerOptions config.ScannerOption
@@ -168,7 +168,7 @@ func initializeScanner(ctx context.Context, opt Option) (scanner.Scanner, func()
if opt.Input != "" {
// Scan tar file
s, err := initializeArchiveScanner(ctx, opt.Input, remoteCache, client.CustomHeaders(opt.CustomHeaders),
client.RemoteURL(opt.RemoteAddr), artifactOpt, configScannerOptions)
client.RemoteURL(opt.RemoteAddr), client.Insecure(opt.Insecure), artifactOpt, configScannerOptions)
if err != nil {
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the archive scanner: %w", err)
}
@@ -182,7 +182,7 @@ func initializeScanner(ctx context.Context, opt Option) (scanner.Scanner, func()
}
s, cleanup, err := initializeDockerScanner(ctx, opt.Target, remoteCache, client.CustomHeaders(opt.CustomHeaders),
client.RemoteURL(opt.RemoteAddr), dockerOpt, artifactOpt, configScannerOptions)
client.RemoteURL(opt.RemoteAddr), client.Insecure(opt.Insecure), dockerOpt, artifactOpt, configScannerOptions)
if err != nil {
return scanner.Scanner{}, nil, xerrors.Errorf("unable to initialize the docker scanner: %w", err)
}

View File

@@ -1,6 +1,6 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:generate wire
//go:build !wireinject
// +build !wireinject
@@ -22,8 +22,8 @@ import (
// Injectors from inject.go:
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
scannerScanner := client.NewProtobufClient(url)
func initializeDockerScanner(ctx context.Context, imageName string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, insecure client.Insecure, dockerOpt types.DockerOption, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, func(), error) {
scannerScanner := client.NewProtobufClient(url, insecure)
clientScanner := client.NewScanner(customHeaders, scannerScanner)
typesImage, cleanup, err := image.NewDockerImage(ctx, imageName, dockerOpt)
if err != nil {
@@ -40,8 +40,8 @@ func initializeDockerScanner(ctx context.Context, imageName string, artifactCach
}, nil
}
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, error) {
scannerScanner := client.NewProtobufClient(url)
func initializeArchiveScanner(ctx context.Context, filePath string, artifactCache cache.ArtifactCache, customHeaders client.CustomHeaders, url client.RemoteURL, insecure client.Insecure, artifactOption artifact.Option, configScannerOption config.ScannerOption) (scanner.Scanner, error) {
scannerScanner := client.NewProtobufClient(url, insecure)
clientScanner := client.NewScanner(customHeaders, scannerScanner)
typesImage, err := image.NewArchiveImage(filePath)
if err != nil {

View File

@@ -2,15 +2,15 @@ package client
import (
"context"
"crypto/tls"
"net/http"
ftypes "github.com/aquasecurity/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/google/wire"
"golang.org/x/xerrors"
ftypes "github.com/aquasecurity/fanal/types"
r "github.com/aquasecurity/trivy/pkg/rpc"
rpc "github.com/aquasecurity/trivy/rpc/scanner"
)
@@ -24,9 +24,20 @@ var SuperSet = wire.NewSet(
// RemoteURL for RPC remote host
type RemoteURL string
// Insecure for RPC remote host
type Insecure bool
// NewProtobufClient is the factory method to return RPC scanner
func NewProtobufClient(remoteURL RemoteURL) rpc.Scanner {
return rpc.NewScannerProtobufClient(string(remoteURL), &http.Client{})
func NewProtobufClient(remoteURL RemoteURL, insecure Insecure) rpc.Scanner {
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: bool(insecure),
},
},
}
return rpc.NewScannerProtobufClient(string(remoteURL), httpClient)
}
// CustomHeaders for holding HTTP headers

View File

@@ -3,6 +3,8 @@ package client
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/golang/protobuf/ptypes/timestamp"
@@ -283,3 +285,48 @@ func TestScanner_Scan(t *testing.T) {
})
}
}
func TestScanner_ScanServerInsecure(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
defer ts.Close()
type args struct {
request *scanner.ScanRequest
insecure bool
}
tests := []struct {
name string
args args
wantErr string
}{
{
name: "happy path",
args: args{
request: &scanner.ScanRequest{},
insecure: true,
},
},
{
name: "sad path",
args: args{
request: &scanner.ScanRequest{},
insecure: false,
},
wantErr: "certificate signed by unknown authority",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := NewProtobufClient(RemoteURL(ts.URL), Insecure(tt.args.insecure))
_, err := s.Scan(context.Background(), tt.args.request)
if tt.wantErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tt.wantErr)
return
}
require.NoError(t, err)
})
}
}