Skip to content

Commit

Permalink
feat(image): add support for passing architecture and OS (#3012)
Browse files Browse the repository at this point in the history
Co-authored-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
ShubhamPalriwala and knqyf263 committed Oct 25, 2022
1 parent 0501e70 commit 8ae4627
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 5 deletions.
42 changes: 42 additions & 0 deletions docs/docs/vulnerability/examples/others.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,48 @@ If your image contains lock files which are not maintained by you, you can skip
$ trivy image --skip-dirs /var/lib/gems/2.5.0/gems/fluent-plugin-detect-exceptions-0.0.13 --skip-dirs "/var/lib/gems/2.5.0/gems/http_parser.rb-0.6.0" quay.io/fluentd_elasticsearch/fluentd:v2.9.0
```

## Scan Image on a specific Architecture and OS

By default, Trivy loads an image on a "linux/amd64" machine.
To customise this, pass a `--platform` argument in the format OS/Architecture for the image:

```
$ trivy image --platform=os/architecture [YOUR_IMAGE_NAME]
```

For example:

```
$ trivy image --platform=linux/arm alpine:3.16.1
```

<details>
<summary>Result</summary>

```
2022-10-25T21:00:50.972+0300 INFO Vulnerability scanning is enabled
2022-10-25T21:00:50.972+0300 INFO Secret scanning is enabled
2022-10-25T21:00:50.972+0300 INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning
2022-10-25T21:00:50.972+0300 INFO Please see also https://aquasecurity.github.io/trivy/dev/docs/secret/scanning/#recommendation for faster secret detection
2022-10-25T21:00:56.190+0300 INFO Detected OS: alpine
2022-10-25T21:00:56.190+0300 INFO Detecting Alpine vulnerabilities...
2022-10-25T21:00:56.191+0300 INFO Number of language-specific files: 0
alpine:3.16.1 (alpine 3.16.1)
=============================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)
┌─────────┬────────────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├─────────┼────────────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────────┤
│ zlib │ CVE-2022-37434 │ CRITICAL │ 1.2.12-r1 │ 1.2.12-r2 │ zlib: heap-based buffer over-read and overflow in inflate() │
│ │ │ │ │ │ in inflate.c via a... │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-37434 │
└─────────┴────────────────┴──────────┴───────────────────┴───────────────┴─────────────────────────────────────────────────────────────┘
```

</details>

## File patterns
When a directory is given as an input, Trivy will recursively look for and test all files based on file patterns.
The default file patterns are [here](../../misconfiguration/custom/index.md).
Expand Down
1 change: 0 additions & 1 deletion docs/docs/vulnerability/scanning/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,3 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)

</details>


2 changes: 2 additions & 0 deletions pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
VulnType: opts.VulnType,
SecurityChecks: opts.SecurityChecks,
ScanRemovedPackages: opts.ScanRemovedPkgs, // this is valid only for 'image' subcommand
Platform: opts.Platform, // this is valid only for 'image' subcommand
ListAllPackages: opts.ListAllPkgs,
LicenseCategories: opts.LicenseCategories,
FilePatterns: opts.FilePatterns,
Expand Down Expand Up @@ -517,6 +518,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
RepoTag: opts.RepoTag,
SBOMSources: opts.SBOMSources,
RekorURL: opts.RekorURL,
Platform: opts.Platform,

// For misconfiguration scanning
MisconfScannerOption: configScannerOptions,
Expand Down
4 changes: 2 additions & 2 deletions pkg/commands/artifact/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// imageStandaloneScanner initializes a container image scanner in standalone mode
// $ trivy image alpine:3.15
func imageStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.Scanner, func(), error) {
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS)
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS, conf.ArtifactOption.Platform)
if err != nil {
return scanner.Scanner{}, nil, err
}
Expand Down Expand Up @@ -40,7 +40,7 @@ func archiveStandaloneScanner(ctx context.Context, conf ScannerConfig) (scanner.
func imageRemoteScanner(ctx context.Context, conf ScannerConfig) (
scanner.Scanner, func(), error) {
// Scan an image in Docker Engine, Docker Registry, etc.
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS)
dockerOpt, err := types.GetDockerOption(conf.ArtifactOption.InsecureSkipTLS, conf.ArtifactOption.Platform)
if err != nil {
return scanner.Scanner{}, nil, err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/fanal/artifact/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Option struct {
RepoTag string
SBOMSources []string
RekorURL string
Platform string

MisconfScannerOption misconf.ScannerOption
SecretScannerOption analyzer.SecretScannerOption
Expand Down
45 changes: 45 additions & 0 deletions pkg/fanal/image/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,48 @@ func TestNewArchiveImage(t *testing.T) {
})
}
}

func TestDockerPlatformArguments(t *testing.T) {
tr := setupPrivateRegistry()
defer tr.Close()

serverAddr := tr.Listener.Addr().String()

type args struct {
option types.DockerOption
}
tests := []struct {
name string
args args
want v1.Image
wantErr string
}{
{
name: "happy path with valid platform",
args: args{
option: types.DockerOption{
UserName: "test",
Password: "testpass",
NonSSL: true,
InsecureSkipTLSVerify: true,
Platform: "arm/linux",

This comment has been minimized.

Copy link
@varanasikalyan

varanasikalyan Oct 27, 2022

Contributor

is this convention correct ?"arch/os" or the other way around "os/arch"

eg: arm/linux or linux/arm

},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
imageName := fmt.Sprintf("%s/library/alpine:3.10", serverAddr)

_, cleanup, err := NewContainerImage(context.Background(), imageName, tt.args.option)
defer cleanup()

if tt.wantErr != "" {
assert.NotNil(t, err)
assert.Contains(t, err.Error(), tt.wantErr, err)
} else {
assert.NoError(t, err)
}
})
}
}
8 changes: 8 additions & 0 deletions pkg/fanal/image/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ func tryRemote(ctx context.Context, imageName string, ref name.Reference, option
remoteOpts = append(remoteOpts, remote.WithTransport(t))
}

if option.Platform != "" {
s, err := v1.ParsePlatform(option.Platform)
if err != nil {
return nil, err
}
remoteOpts = append(remoteOpts, remote.WithPlatform(*s))
}

domain := ref.Context().RegistryStr()
auth := token.GetToken(ctx, domain, option)

Expand Down
3 changes: 3 additions & 0 deletions pkg/fanal/types/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ type DockerOption struct {
// SSL/TLS
InsecureSkipTLSVerify bool
NonSSL bool

// Architecture
Platform string
}
13 changes: 12 additions & 1 deletion pkg/flag/image_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,32 @@ var (
Value: "",
Usage: "input file path instead of image name",
}

PlatformFlag = Flag{
Name: "platform",
ConfigName: "image.platform",
Value: "",
Usage: "set platform in the form os/arch if image is multi-platform capable",
}
)

type ImageFlagGroup struct {
Input *Flag // local image archive
ScanRemovedPkgs *Flag
Platform *Flag
}

type ImageOptions struct {
Input string
ScanRemovedPkgs bool
Platform string
}

func NewImageFlagGroup() *ImageFlagGroup {
return &ImageFlagGroup{
Input: &InputFlag,
ScanRemovedPkgs: &ScanRemovedPkgsFlag,
Platform: &PlatformFlag,
}
}

Expand All @@ -42,12 +52,13 @@ func (f *ImageFlagGroup) Name() string {
}

func (f *ImageFlagGroup) Flags() []*Flag {
return []*Flag{f.Input, f.ScanRemovedPkgs}
return []*Flag{f.Input, f.ScanRemovedPkgs, f.Platform}
}

func (f *ImageFlagGroup) ToOptions() ImageOptions {
return ImageOptions{
Input: getString(f.Input),
ScanRemovedPkgs: getBool(f.ScanRemovedPkgs),
Platform: getString(f.Platform),
}
}
3 changes: 2 additions & 1 deletion pkg/types/docker_conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type DockerConfig struct {
}

// GetDockerOption returns the Docker scanning options using DockerConfig
func GetDockerOption(insecureTlsSkip bool) (types.DockerOption, error) {
func GetDockerOption(insecureTlsSkip bool, Platform string) (types.DockerOption, error) {
cfg := DockerConfig{}
if err := env.Parse(&cfg); err != nil {
return types.DockerOption{}, xerrors.Errorf("unable to parse environment variables: %w", err)
Expand All @@ -28,5 +28,6 @@ func GetDockerOption(insecureTlsSkip bool) (types.DockerOption, error) {
RegistryToken: cfg.RegistryToken,
InsecureSkipTLSVerify: insecureTlsSkip,
NonSSL: cfg.NonSSL,
Platform: Platform,
}, nil
}
1 change: 1 addition & 0 deletions pkg/types/scanoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type ScanOptions struct {
VulnType []string
SecurityChecks []string
ScanRemovedPackages bool
Platform string
ListAllPackages bool
LicenseCategories map[types.LicenseCategory][]string
FilePatterns []string
Expand Down

0 comments on commit 8ae4627

Please sign in to comment.