Skip to content

Commit

Permalink
feat: support plugins (#878)
Browse files Browse the repository at this point in the history
* fix(log): set the default logger

* feat: support plugins

* feat(plugin): add run command

* feat(plugin): add uninstall command

* test(plugin): add tests

* chore(ci): pin go version

* chore(ci): disable G204

* refactor: fix lint issues

* feat(plugin): skip downloading installed plugins

* feat: add TRIVY_RUN_AS_PLUGIN

* support Ubuntu 20.10 (#876)

* docs(README): update ubuntu versions (#877)

* add MkDocs implementation (#870)

* mkdocs: add top level nav

* mkdocs: add installation nav

* mkdocs: add quick-start nav

* mkdocs: add examples nav

* mkdocs: add CI nav

* mkdocs: add vuln-detection nav

* mkdocs: add comparison nav

* mkdocs: add usage nav

* mkdocs: add migration nav

* mkdocs: add FAQ nav

* mkdocs: add mkdocs.yml

* mkdocs: add github workflow

* docs: update documents

* fix links

* chore(ci): use ORG_GITHUB_TOKEN

* chore(mkdocs): use mike

* chore(ci): support dev

* chore(ci): documentation test

Co-authored-by: knqyf263 <[email protected]>

* docs: add plugins

* chore: remove stale workflow

* refactor: fix lint issues

Co-authored-by: Huang Huang <[email protected]>
Co-authored-by: aprp <[email protected]>
  • Loading branch information
3 people authored Mar 10, 2021
1 parent 37edc66 commit 8b3b5d0
Show file tree
Hide file tree
Showing 47 changed files with 1,044 additions and 155 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: ${{ env.GO_VERSION }}

- name: Lint
uses: golangci/golangci-lint-action@v2
with:
Expand Down
5 changes: 4 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ issues:
- linters:
- gosec
text: "Deferring unsafe method"
- linters:
- gosec
text: "G204: Subprocess launched with variable"
- linters:
- errcheck
text: "Close` is not checked"
Expand All @@ -68,4 +71,4 @@ issues:
exclude:
- "should have a package comment, unless it's in another file for this package"
exclude-use-default: false
max-same-issues: 0
max-same-issues: 0
7 changes: 1 addition & 6 deletions cmd/trivy/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package main

import (
l "log"
"os"

"github.com/aquasecurity/trivy/internal"

"github.com/aquasecurity/trivy/pkg/log"
)

Expand All @@ -17,9 +15,6 @@ func main() {
app := internal.NewApp(version)
err := app.Run(os.Args)
if err != nil {
if log.Logger != nil {
log.Fatal(err)
}
l.Fatal(err)
log.Fatal(err)
}
}
173 changes: 173 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Plugins
Trivy provides a plugin feature to allow others to extend the Trivy CLI without the need to change the Trivycode base.
This plugin system was inspired by the plugin system used in [kubectl][kubectl], [Helm][helm], and [Conftest][conftest].

## Overview
Trivy plugins are add-on tools that integrate seamlessly with Trivy.
They provide a way to extend the core feature set of Trivy, but without requiring every new feature to be written in Go and added to the core tool.

- They can be added and removed from a Trivy installation without impacting the core Trivy tool.
- They can be written in any programming language.
- They integrate with Trivy, and will show up in Trivy help and subcommands.

!!! warning
Trivy plugins available in public are not audited for security.
You should install and run third-party plugins at your own risk, since they are arbitrary programs running on your machine.


## Installing a Plugin
A plugin can be installed using the `trivy plugin install` command.
This command takes a url and will download the plugin and install it in the plugin cache.

Trivy adheres to the XDG specification, so the location depends on whether XDG_DATA_HOME is set.
Trivy will now search XDG_DATA_HOME for the location of the Trivy plugins cache.
The preference order is as follows:

- XDG_DATA_HOME if set and .trivy/plugins exists within the XDG_DATA_HOME dir
- ~/.trivy/plugins

Under the hood Trivy leverages [go-getter][go-getter] to download plugins.
This means the following protocols are supported for downloading plugins:

- OCI Registries
- Local Files
- Git
- HTTP/HTTPS
- Mercurial
- Amazon S3
- Google Cloud Storage

For example, to download the Kubernetes Trivy plugin you can execute the following command:

```bash
$ trivy plugin install github.com/aquasecurity/trivy-plugin-kubectl
```
## Using Plugins
Once the plugin is installed, Trivy will load all available plugins in the cache on the start of the next Trivy execution.
A plugin will be made in the Trivy CLI based on the plugin name.
To display all plugins, you can list them by `trivy --help`

```bash
$ trivy --help
NAME:
trivy - A simple and comprehensive vulnerability scanner for containers

USAGE:
trivy [global options] command [command options] target

VERSION:
dev

COMMANDS:
image, i scan an image
filesystem, fs scan local filesystem
repository, repo scan remote repository
client, c client mode
server, s server mode
plugin, p manage plugins
kubectl scan kubectl resources
help, h Shows a list of commands or help for one command
```

As shown above, `kubectl` subcommand exists in the `COMMANDS` section.
To call the kubectl plugin and scan existing Kubernetes deployments, you can execute the following command:

```
$ trivy kubectl deployment <deployment-id> -- --ignore-unfixed --severity CRITICAL
```

Internally the kubectl plugin calls the kubectl binary to fetch information about that deployment and passes the using images to Trivy.
You can see the detail [here][trivy-plugin-kubectl].

If you want to omit even the subcommand, you can use `TRIVY_RUN_AS_PLUGIN` environment variable.

```bash
$ TRIVY_RUN_AS_PLUGIN=kubectl trivy job your-job -- --format json
```

## Installing and Running Plugins on the fly
`trivy plugin run` installs a plugin and runs it on the fly.
If the plugin is already present in the cache, the installation is skipped.

```bash
trivy plugin run github.com/aquasecurity/trivy-plugin-kubectl pod your-pod -- --exit-code 1
```

## Uninstalling Plugins
Specify a plugin name with `trivy plugin uninstall` command.

```bash
$ trivy plugin uninstall kubectl
```

## Building Plugins
Each plugin has a top-level directory, and then a plugin.yaml file.

```bash
your-plugin/
|
|- plugin.yaml
|- your-plugin.sh
```

In the example above, the plugin is contained inside of a directory named `your-plugin`.
It has two files: plugin.yaml (required) and an executable script, your-plugin.sh (optional).

The core of a plugin is a simple YAML file named plugin.yaml.
Here is an example YAML of trivy-plugin-kubectl plugin that adds support for Kubernetes scanning.

```yaml
name: "kubectl"
repository: github.com/aquasecurity/trivy-plugin-kubectl
version: "0.1.0"
usage: scan kubectl resources
description: |-
A Trivy plugin that scans the images of a kubernetes resource.
Usage: trivy kubectl TYPE[.VERSION][.GROUP] NAME
platforms:
- selector: # optional
os: darwin
arch: amd64
uri: ./trivy-kubectl # where the execution file is (local file, http, git, etc.)
bin: ./trivy-kubectl # path to the execution file
- selector: # optional
os: linux
arch: amd64
uri: https://github.com/aquasecurity/trivy-plugin-kubectl/releases/download/v0.1.0/trivy-kubectl.tar.gz
bin: ./trivy-kubectl
```
The `plugin.yaml` field should contain the following information:

- name: The name of the plugin. This also determines how the plugin will be made available in the Trivy CLI. For example, if the plugin is named kubectl, you can call the plugin with `trivy kubectl`. (required)
- version: The version of the plugin. (required)
- usage: A short usage description. (required)
- description: A long description of the plugin. This is where you could provide a helpful documentation of your plugin. (required)
- platforms: (required)
- selector: The OS/Architecture specific variations of a execution file. (optional)
- os: OS information based on GOOS (linux, darwin, etc.) (optional)
- arch: The architecture information based on GOARCH (amd64, arm64, etc.) (optional)
- uri: Where the executable file is. Relative path from the root directory of the plugin or remote URL such as HTTP and S3. (required)
- bin: Which file to call when the plugin is executed. Relative path from the root directory of the plugin. (required)

The following rules will apply in deciding which platform to select:

- If both `os` and `arch` under `selector` match the current platform, search will stop and the platform will be used.
- If `selector` is not present, the platform will be used.
- If `os` matches and there is no more specific `arch` match, the platform will be used.
- If no `platform` match is found, Trivy will exit with an error.

After determining platform, Trivy will download the execution file from `uri` and store it in the plugin cache.
When the plugin is called via Trivy CLI, `bin` command will be executed.

The plugin is responsible for handling flags and arguments. Any arguments are passed to the plugin from the `trivy` command.

## Example
https://github.com/aquasecurity/trivy-plugin-kubectl

[kubectl]: https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/
[helm]: https://helm.sh/docs/topics/plugins/
[conftest]: https://www.conftest.dev/plugins/
[go-getter]: https://github.com/hashicorp/go-getter
[trivy-plugin-kubectl]: https://github.com/aquasecurity/trivy-plugin-kubectl

5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ require (
github.com/docker/docker v20.10.3+incompatible
github.com/docker/go-connections v0.4.0
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d // indirect
github.com/elazarl/goproxy/ext v0.0.0-20200809112317-0581fc3aee2d // indirect
github.com/go-redis/redis/v8 v8.4.0
github.com/goccy/go-yaml v1.8.2 // indirect
github.com/golang/protobuf v1.4.3
github.com/google/go-containerregistry v0.1.2
github.com/google/go-github/v28 v28.1.1
github.com/google/wire v0.4.0
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/hashicorp/go-getter v1.5.2
github.com/huandu/xstrings v1.3.2 // indirect
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
Expand All @@ -36,6 +36,7 @@ require (
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/olekukonko/tablewriter v0.0.4
github.com/open-policy-agent/opa v0.25.2
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/smartystreets/assertions v1.2.0 // indirect
github.com/spf13/afero v1.2.2
github.com/stretchr/objx v0.3.0 // indirect
Expand All @@ -49,6 +50,6 @@ require (
google.golang.org/protobuf v1.25.0
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
)
Loading

0 comments on commit 8b3b5d0

Please sign in to comment.