From f75784554ca0268f0f388c3941d6e0760e5a52f6 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 16:47:02 +0400 Subject: [PATCH 01/19] feat(cli): add auth subcommand Signed-off-by: knqyf263 --- pkg/commands/app.go | 54 ++++++++++++++++++++++++++++ pkg/commands/auth/run.go | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 pkg/commands/auth/run.go diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 23b44fdec553..0c0799598796 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -15,6 +15,7 @@ import ( "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/commands/artifact" + "github.com/aquasecurity/trivy/pkg/commands/auth" "github.com/aquasecurity/trivy/pkg/commands/clean" "github.com/aquasecurity/trivy/pkg/commands/convert" "github.com/aquasecurity/trivy/pkg/commands/server" @@ -99,6 +100,7 @@ func NewApp() *cobra.Command { NewVersionCommand(globalFlags), NewVMCommand(globalFlags), NewCleanCommand(globalFlags), + NewAuthCommand(globalFlags), NewVEXCommand(globalFlags), ) @@ -1232,6 +1234,58 @@ func NewCleanCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { return cmd } +func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { + cmd := &cobra.Command{ + Use: "auth [flags]", + GroupID: groupUtility, + Short: "Authentication", + SilenceErrors: true, + SilenceUsage: true, + } + + loginFlags := &flag.Flags{ + GlobalFlagGroup: globalFlags, + RegistryFlagGroup: flag.NewRegistryFlagGroup(), + } + loginFlags.RegistryFlagGroup.RegistryToken = nil // disable '--registry-token' + loginCmd := &cobra.Command{ + Use: "login SERVER", + Short: "Log in to a registry", + SilenceErrors: true, + SilenceUsage: true, + Args: cobra.ExactArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + if err := loginFlags.Bind(cmd); err != nil { + return xerrors.Errorf("flag bind error: %w", err) + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + loginOpts, err := loginFlags.ToOptions(args) + if err != nil { + return xerrors.Errorf("flag error: %w", err) + } + return auth.Login(cmd.Context(), args[0], loginOpts) + }, + } + logoutCmd := &cobra.Command{ + Use: "logout SERVER", + Short: "Log out of a registry", + SilenceErrors: true, + SilenceUsage: true, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return auth.Logout(cmd.Context(), args[0]) + }, + } + loginFlags.AddFlags(loginCmd) + cmd.AddCommand(loginCmd, logoutCmd) + + cmd.SetFlagErrorFunc(flagErrorFunc) + + return cmd +} + func NewVEXCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { vexFlags := &flag.Flags{ GlobalFlagGroup: globalFlags, diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go new file mode 100644 index 000000000000..1b2981280362 --- /dev/null +++ b/pkg/commands/auth/run.go @@ -0,0 +1,77 @@ +package auth + +import ( + "context" + "os" + + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/types" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/flag" + "github.com/aquasecurity/trivy/pkg/log" +) + +func Login(_ context.Context, registry string, opts flag.Options) error { + if len(opts.Credentials) == 0 { + return xerrors.New("username and password required") + } else if len(opts.Credentials) > 1 { + return xerrors.New("multiple credentials are not allowed") + } + + reg, err := name.NewRegistry(registry) + if err != nil { + return xerrors.Errorf("failed to parse registry: %w", err) + } + serverAddress := reg.Name() + + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) + if err != nil { + return xerrors.Errorf("failed to load docker config: %w", err) + } + creds := cf.GetCredentialsStore(serverAddress) + if serverAddress == name.DefaultRegistry { + serverAddress = authn.DefaultAuthKey + } + if err := creds.Store(types.AuthConfig{ + ServerAddress: serverAddress, + Username: opts.Credentials[0].Username, + Password: opts.Credentials[0].Password, + }); err != nil { + return xerrors.Errorf("failed to store credentials: %w", err) + } + + if err := cf.Save(); err != nil { + return xerrors.Errorf("failed to save docker config: %w", err) + } + log.Info("Logged in", log.FilePath(cf.Filename)) + return nil +} + +func Logout(_ context.Context, registry string) error { + reg, err := name.NewRegistry(registry) + if err != nil { + return err + } + serverAddress := reg.Name() + + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) + if err != nil { + return xerrors.Errorf("failed to load docker config: %w", err) + } + creds := cf.GetCredentialsStore(serverAddress) + if serverAddress == name.DefaultRegistry { + serverAddress = authn.DefaultAuthKey + } + if err := creds.Erase(serverAddress); err != nil { + return xerrors.Errorf("failed to delete credentials: %w", err) + } + + if err := cf.Save(); err != nil { + return xerrors.Errorf("failed to save docker config: %w", err) + } + log.Info("Logged out", log.FilePath(cf.Filename)) + return nil +} From 9d21817e8c19660508f37347f72ff92d4c12a623 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 16:47:26 +0400 Subject: [PATCH 02/19] feat: add "--password-stdin" Signed-off-by: knqyf263 --- pkg/flag/registry_flags.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index 552eaf4276d6..e8bea6e8553a 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -1,6 +1,8 @@ package flag import ( + "io" + "os" "strings" "golang.org/x/xerrors" @@ -19,6 +21,11 @@ var ( ConfigName: "registry.password", Usage: "password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons.", } + PasswordStdinFlag = Flag[bool]{ + Name: "password-stdin", + ConfigName: "registry.password-stdin", + Usage: "password from stdin", + } RegistryTokenFlag = Flag[string]{ Name: "registry-token", ConfigName: "registry.token", @@ -29,6 +36,7 @@ var ( type RegistryFlagGroup struct { Username *Flag[[]string] Password *Flag[[]string] + PasswordStdin *Flag[bool] RegistryToken *Flag[string] } @@ -41,6 +49,7 @@ func NewRegistryFlagGroup() *RegistryFlagGroup { return &RegistryFlagGroup{ Username: UsernameFlag.Clone(), Password: PasswordFlag.Clone(), + PasswordStdin: PasswordStdinFlag.Clone(), RegistryToken: RegistryTokenFlag.Clone(), } } @@ -53,6 +62,7 @@ func (f *RegistryFlagGroup) Flags() []Flagger { return []Flagger{ f.Username, f.Password, + f.PasswordStdin, f.RegistryToken, } } @@ -65,6 +75,14 @@ func (f *RegistryFlagGroup) ToOptions() (RegistryOptions, error) { var credentials []types.Credential users := f.Username.Value() passwords := f.Password.Value() + if f.PasswordStdin.Value() { + contents, err := io.ReadAll(os.Stdin) + if err != nil { + return RegistryOptions{}, xerrors.Errorf("failed to read from stdin: %w", err) + } + // "--password-stdin" doesn't support comma-separated passwords + passwords = []string{strings.TrimRight(string(contents), "\r\n")} + } if len(users) != len(passwords) { return RegistryOptions{}, xerrors.New("the length of usernames and passwords must match") } From ce4fe982a02f1f8763929a2548c645f41d08ab69 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 16:56:07 +0400 Subject: [PATCH 03/19] test: delete unused params Signed-off-by: knqyf263 --- integration/registry_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/integration/registry_test.go b/integration/registry_test.go index 3831ea9a280e..3faf661475c6 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -164,7 +164,6 @@ func TestRegistry(t *testing.T) { imageFile: "testdata/fixtures/images/alpine-310.tar.gz", os: "alpine 3.10.2", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, @@ -189,7 +188,6 @@ func TestRegistry(t *testing.T) { imageFile: "testdata/fixtures/images/amazon-2.tar.gz", os: "amazon 2 (Karoo)", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, @@ -201,7 +199,6 @@ func TestRegistry(t *testing.T) { imageFile: "testdata/fixtures/images/debian-buster.tar.gz", os: "debian 10.1", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, From b671a80482983d3549fd52c188f0b045e8aab577 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 17:12:38 +0400 Subject: [PATCH 04/19] test(integration): auth with 'trivy auth login' Signed-off-by: knqyf263 --- integration/registry_test.go | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/integration/registry_test.go b/integration/registry_test.go index 3faf661475c6..7b5d02db3a6b 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -117,6 +117,7 @@ type registryOption struct { Username string Password string RegistryToken bool + AuthLogin bool } func TestRegistry(t *testing.T) { @@ -182,6 +183,18 @@ func TestRegistry(t *testing.T) { }, golden: "testdata/alpine-310.json.golden", }, + { + name: "authenticate with 'trivy auth login'", + imageName: "alpine:3.10", + imageFile: "testdata/fixtures/images/alpine-310.tar.gz", + os: "alpine 3.10.2", + option: registryOption{ + Username: authUsername, + Password: authPassword, + AuthLogin: true, + }, + golden: "testdata/alpine-310.json.golden", + }, { name: "amazonlinux 2", imageName: "amazonlinux:2", @@ -223,6 +236,7 @@ func TestRegistry(t *testing.T) { require.NoError(t, err) osArgs, err := scan(t, imageRef, baseDir, tt.option) + require.NoError(t, err) // Run Trivy runTest(t, osArgs, tt.golden, "", types.FormatJSON, runOptions{ @@ -259,7 +273,7 @@ func scan(t *testing.T, imageRef name.Reference, baseDir string, opt registryOpt "json", "--image-src", "remote", - "--skip-update", + "--skip-db-update", imageRef.Name(), } @@ -270,14 +284,29 @@ func setupEnv(t *testing.T, imageRef name.Reference, baseDir string, opt registr t.Setenv("TRIVY_INSECURE", "true") if opt.Username != "" && opt.Password != "" { - if opt.RegistryToken { + switch { + case opt.RegistryToken: // Get a registry token in advance token, err := requestRegistryToken(imageRef, baseDir, opt) if err != nil { return err } t.Setenv("TRIVY_REGISTRY_TOKEN", token) - } else { + case opt.AuthLogin: + t.Setenv("DOCKER_CONFIG", t.TempDir()) + err := execute([]string{ + "auth", + "login", + "--username", + opt.Username, + "--password", + opt.Password, + imageRef.Context().RegistryStr(), + }) + if err != nil { + return err + } + default: t.Setenv("TRIVY_USERNAME", opt.Username) t.Setenv("TRIVY_PASSWORD", opt.Password) } From 5a6caa18a46aac6e8788d19501d0064d905a9d49 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 17:53:18 +0400 Subject: [PATCH 05/19] test: add unit tests Signed-off-by: knqyf263 --- pkg/commands/auth/run.go | 2 +- pkg/commands/auth/run_test.go | 133 ++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 pkg/commands/auth/run_test.go diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go index 1b2981280362..b606ae758ba5 100644 --- a/pkg/commands/auth/run.go +++ b/pkg/commands/auth/run.go @@ -53,7 +53,7 @@ func Login(_ context.Context, registry string, opts flag.Options) error { func Logout(_ context.Context, registry string) error { reg, err := name.NewRegistry(registry) if err != nil { - return err + return xerrors.Errorf("failed to parse registry: %w", err) } serverAddress := reg.Name() diff --git a/pkg/commands/auth/run_test.go b/pkg/commands/auth/run_test.go new file mode 100644 index 000000000000..d3dfb5b80c56 --- /dev/null +++ b/pkg/commands/auth/run_test.go @@ -0,0 +1,133 @@ +package auth_test + +import ( + "context" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/commands/auth" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/flag" +) + +func TestLogin(t *testing.T) { + type args struct { + registry string + opts flag.Options + } + tests := []struct { + name string + args args + wantErr string + }{ + { + name: "single credential", + args: args{ + registry: "auth.test", + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user", + Password: "pass", + }, + }, + }, + }, + }, + }, + { + name: "multiple credentials", + args: args{ + registry: "auth.test", + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user1", + Password: "pass1", + }, + { + Username: "user2", + Password: "pass2", + }, + }, + }, + }, + }, + wantErr: "multiple credentials are not allowed", + }, + { + name: "no credentials", + args: args{ + registry: "auth.test", + opts: flag.Options{}, + }, + wantErr: "username and password required", + }, + { + name: "invalid registry", + args: args{ + registry: "aaa://invalid.test", + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user", + Password: "pass", + }, + }, + }, + }, + }, + wantErr: "registries must be valid RFC 3986 URI authorities", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set the DOCKER_CONFIG environment variable to a temporary directory + // so that the test does not interfere with the user's configuration. + t.Setenv("DOCKER_CONFIG", filepath.Join(t.TempDir(), "config.json")) + + err := auth.Login(context.Background(), tt.args.registry, tt.args.opts) + if tt.wantErr != "" { + require.ErrorContains(t, err, tt.wantErr) + return + } + require.NoError(t, err) + }) + } +} + +func TestLogout(t *testing.T) { + // Set the DOCKER_CONFIG environment variable to a temporary directory + // so that the test does not interfere with the user's configuration. + t.Setenv("DOCKER_CONFIG", t.TempDir()) + + t.Run("success", func(t *testing.T) { + err := auth.Login(context.Background(), "auth.test", flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user", + Password: "pass", + }, + }, + }, + }) + require.NoError(t, err) + err = auth.Logout(context.Background(), "auth.test") + require.NoError(t, err) + }) + t.Run("not found", func(t *testing.T) { + err := auth.Logout(context.Background(), "notfound.test") + require.NoError(t, err) // Return an error if "credsStore" is "osxkeychain". + }) + + t.Run("invalid registry", func(t *testing.T) { + err := auth.Logout(context.Background(), "aaa://invalid.test") + require.ErrorContains(t, err, "registries must be valid RFC 3986 URI authorities") + }) +} From 6d898d6718ca3dd13564118b702115f48711af14 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 17:55:17 +0400 Subject: [PATCH 06/19] docs: use 'trivy auth login' Signed-off-by: knqyf263 --- contrib/Trivy.gitlab-ci.yml | 2 +- .../docs/advanced/private-registries/index.md | 37 +++++++++++-------- docs/docs/target/container_image.md | 2 +- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/contrib/Trivy.gitlab-ci.yml b/contrib/Trivy.gitlab-ci.yml index 66225b0dac06..a62e26301a20 100644 --- a/contrib/Trivy.gitlab-ci.yml +++ b/contrib/Trivy.gitlab-ci.yml @@ -12,9 +12,9 @@ Trivy_container_scanning: before_script: - export TRIVY_VERSION=${TRIVY_VERSION:-v0.19.2} - apk add --no-cache curl docker-cli - - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin ${TRIVY_VERSION} - curl -sSL -o /tmp/trivy-gitlab.tpl https://github.com/aquasecurity/trivy/raw/${TRIVY_VERSION}/contrib/gitlab.tpl + - trivy auth login --username "$CI_REGISTRY_USER" --password "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template "@/tmp/trivy-gitlab.tpl" -o gl-container-scanning-report.json $IMAGE cache: diff --git a/docs/docs/advanced/private-registries/index.md b/docs/docs/advanced/private-registries/index.md index 7d5a594cf5b6..8b22430bb570 100644 --- a/docs/docs/advanced/private-registries/index.md +++ b/docs/docs/advanced/private-registries/index.md @@ -1,13 +1,30 @@ Trivy can download images from a private registry without the need for installing Docker or any other 3rd party tools. This makes it easy to run within a CI process. -## Credential -To use Trivy with private images, simply install it and provide your credentials: +## Login +You can log in to a private registry using the `trivy auth login` command. +It uses the Docker configuration file (`~/.docker/config.json`) to store the credentials under the hood, and the configuration file path can be configured by `DOCKER_CONFIG` environment variable. + +```shell +$ cat ~/my_password.txt | trivy auth login --username foo --password-stdin ghcr.io +$ trivy image ghcr.io/your/private_image +``` + +## Passing Credentials +You can also provide your credentials when scanning. ```shell $ TRIVY_USERNAME=YOUR_USERNAME TRIVY_PASSWORD=YOUR_PASSWORD trivy image YOUR_PRIVATE_IMAGE ``` +!!! warning + When passing credentials via environment variables or CLI flags, Trivy will attempt to use these credentials for all registries encountered during scanning, regardless of the target registry. + This can potentially lead to unintended credential exposure. + To mitigate this risk: + + 1. Set credentials cautiously and only when necessary. + 2. Prefer using `trivy auth config` to pre-configure credentials with specific registries, which ensures credentials are only sent to appropriate registries. + Trivy also supports providing credentials through CLI flags: ```shell @@ -17,6 +34,7 @@ $ TRIVY_PASSWORD=YOUR_PASSWORD trivy image --username YOUR_USERNAME YOUR_PRIVATE !!! warning The CLI flag `--password` is available, but its use is not recommended for security reasons. + You can also store your credentials in `trivy.yaml`. For more information, please refer to [the documentation](../../references/configuration/config-file.md). @@ -33,17 +51,4 @@ In the example above, Trivy attempts to use two pairs of credentials: - USERNAME1/PASSWORD1 - USERNAME2/PASSWORD2 -Please note that the number of usernames and passwords must be the same. - -## docker login -If you have Docker configured locally and have set up the credentials, Trivy can access them. - -```shell -$ docker login ghcr.io -Username: -Password: -$ trivy image ghcr.io/your/private_image -``` - -!!! note - `docker login` can be used with any container runtime, such as Podman. +Please note that the number of usernames and passwords must be the same. \ No newline at end of file diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index 94acc954a743..6f514db29fb5 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -297,7 +297,7 @@ Trivy supports registries that comply with the following specifications. - [Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/) - [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec) -You can configure credentials with `docker login`. +You can configure credentials with `trivy auth login`. See [here](../advanced/private-registries/index.md) for the detail. ### Tar Files From 6c6cf077725aef9c2ff3aa4f229c7546c6db2f27 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 18:08:06 +0400 Subject: [PATCH 07/19] docs: add examples Signed-off-by: knqyf263 --- pkg/commands/app.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 0c0799598796..6c32bc5544e5 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -1253,7 +1253,9 @@ func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { Short: "Log in to a registry", SilenceErrors: true, SilenceUsage: true, - Args: cobra.ExactArgs(1), + Example: ` # Log in to reg.example.com + cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com`, + Args: cobra.ExactArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { if err := loginFlags.Bind(cmd); err != nil { return xerrors.Errorf("flag bind error: %w", err) @@ -1273,7 +1275,9 @@ func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { Short: "Log out of a registry", SilenceErrors: true, SilenceUsage: true, - Args: cobra.ExactArgs(1), + Example: ` # Log out of reg.example.com + trivy auth logout reg.example.com`, + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return auth.Logout(cmd.Context(), args[0]) }, From 226b6c4e6ad3bcc8b3cc742dc2eea7b83dc4d5bc Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 18:11:08 +0400 Subject: [PATCH 08/19] chore: go mod tidy Signed-off-by: knqyf263 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index d01ce2a7d4c7..1611c8c7080a 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/cheggaaa/pb/v3 v3.1.5 github.com/containerd/containerd v1.7.22 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 + github.com/docker/cli v27.2.1+incompatible github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.17.0 @@ -210,7 +211,6 @@ require ( github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/docker/cli v27.2.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect From a69a936c37fa15bc28469fdb1e494ba5e549be3e Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Mon, 7 Oct 2024 21:17:24 +0400 Subject: [PATCH 09/19] docs: auto-generate Signed-off-by: knqyf263 --- .../references/configuration/cli/trivy.md | 1 + .../configuration/cli/trivy_auth.md | 29 +++++++++++++ .../configuration/cli/trivy_auth_login.md | 41 +++++++++++++++++++ .../configuration/cli/trivy_auth_logout.md | 38 +++++++++++++++++ .../configuration/cli/trivy_config.md | 1 + .../configuration/cli/trivy_filesystem.md | 1 + .../configuration/cli/trivy_image.md | 1 + .../configuration/cli/trivy_kubernetes.md | 1 + .../configuration/cli/trivy_repository.md | 1 + .../configuration/cli/trivy_rootfs.md | 1 + .../configuration/cli/trivy_server.md | 1 + .../references/configuration/config-file.md | 3 ++ 12 files changed, 119 insertions(+) create mode 100644 docs/docs/references/configuration/cli/trivy_auth.md create mode 100644 docs/docs/references/configuration/cli/trivy_auth_login.md create mode 100644 docs/docs/references/configuration/cli/trivy_auth_logout.md diff --git a/docs/docs/references/configuration/cli/trivy.md b/docs/docs/references/configuration/cli/trivy.md index 3d8ece9cd0e8..2919e43cbe27 100644 --- a/docs/docs/references/configuration/cli/trivy.md +++ b/docs/docs/references/configuration/cli/trivy.md @@ -43,6 +43,7 @@ trivy [global flags] command [flags] target ### SEE ALSO +* [trivy auth](trivy_auth.md) - Authentication * [trivy clean](trivy_clean.md) - Remove cached files * [trivy config](trivy_config.md) - Scan config files for misconfigurations * [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format diff --git a/docs/docs/references/configuration/cli/trivy_auth.md b/docs/docs/references/configuration/cli/trivy_auth.md new file mode 100644 index 000000000000..ba2eaa6a6715 --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth.md @@ -0,0 +1,29 @@ +## trivy auth + +Authentication + +### Options + +``` + -h, --help help for auth +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy](trivy.md) - Unified security scanner +* [trivy auth login](trivy_auth_login.md) - Log in to a registry +* [trivy auth logout](trivy_auth_logout.md) - Log out of a registry + diff --git a/docs/docs/references/configuration/cli/trivy_auth_login.md b/docs/docs/references/configuration/cli/trivy_auth_login.md new file mode 100644 index 000000000000..30e957240f46 --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth_login.md @@ -0,0 +1,41 @@ +## trivy auth login + +Log in to a registry + +``` +trivy auth login SERVER [flags] +``` + +### Examples + +``` + # Log in to reg.example.com + cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com +``` + +### Options + +``` + -h, --help help for login + --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin + --username strings username. Comma-separated usernames allowed. +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy auth](trivy_auth.md) - Authentication + diff --git a/docs/docs/references/configuration/cli/trivy_auth_logout.md b/docs/docs/references/configuration/cli/trivy_auth_logout.md new file mode 100644 index 000000000000..3a25958001cd --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth_logout.md @@ -0,0 +1,38 @@ +## trivy auth logout + +Log out of a registry + +``` +trivy auth logout SERVER [flags] +``` + +### Examples + +``` + # Log out of reg.example.com + trivy auth logout reg.example.com +``` + +### Options + +``` + -h, --help help for logout +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy auth](trivy_auth.md) - Authentication + diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index be7854548496..6f1d2bf4002e 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -39,6 +39,7 @@ trivy config [flags] DIR -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 0abec4990173..d6ef984525c0 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -68,6 +68,7 @@ trivy filesystem [flags] PATH --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index f9095f041572..d3841aaac7a4 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -86,6 +86,7 @@ trivy image [flags] IMAGE_NAME --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --platform string set platform in the form os/arch if image is multi-platform capable diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 99fbc1badaa2..a4921aeeb4a6 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -83,6 +83,7 @@ trivy kubernetes [flags] [CONTEXT] --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --qps float specify the maximum QPS to the master from this client (default 5) diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 821923262dee..60f13d1462b3 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -68,6 +68,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index bf2575af23b9..1e0a42137a6d 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -70,6 +70,7 @@ trivy rootfs [flags] ROOTDIR --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_server.md b/docs/docs/references/configuration/cli/trivy_server.md index b7ada8f2c19b..f156d266c4b1 100644 --- a/docs/docs/references/configuration/cli/trivy_server.md +++ b/docs/docs/references/configuration/cli/trivy_server.md @@ -30,6 +30,7 @@ trivy server [flags] --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 9bc9d4351360..ae04978801b3 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -461,6 +461,9 @@ registry: # Same as '--password' password: [] + # Same as '--password-stdin' + password-stdin: false + # Same as '--registry-token' token: "" From 36f8cd74d88d6106b6ff8794723536d3540e50a0 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 11:43:48 +0400 Subject: [PATCH 10/19] feat: show username Signed-off-by: knqyf263 --- pkg/commands/auth/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go index b606ae758ba5..40e793540f25 100644 --- a/pkg/commands/auth/run.go +++ b/pkg/commands/auth/run.go @@ -46,7 +46,7 @@ func Login(_ context.Context, registry string, opts flag.Options) error { if err := cf.Save(); err != nil { return xerrors.Errorf("failed to save docker config: %w", err) } - log.Info("Logged in", log.FilePath(cf.Filename)) + log.Info("Logged in", log.FilePath(cf.Filename), log.String("username", opts.Credentials[0].Username)) return nil } From 679e3d9198852c642362b2cefd0f6d44eaf95bdc Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 11:47:40 +0400 Subject: [PATCH 11/19] docs: add reference links Signed-off-by: knqyf263 --- mkdocs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkdocs.yml b/mkdocs.yml index abe494df9dd9..1d3d6276e2c3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -158,6 +158,10 @@ nav: - Configuration: - CLI: - Overview: docs/references/configuration/cli/trivy.md + - Auth: + - Auth: docs/references/configuration/cli/trivy_auth.md + - Auth Login: docs/references/configuration/cli/trivy_auth_login.md + - Auth Logout: docs/references/configuration/cli/trivy_auth_logout.md - Clean: docs/references/configuration/cli/trivy_clean.md - Config: docs/references/configuration/cli/trivy_config.md - Convert: docs/references/configuration/cli/trivy_convert.md From ba9642a1486eebd16cbd1590722c776417dd35bb Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Tue, 8 Oct 2024 11:53:16 +0400 Subject: [PATCH 12/19] Update pkg/flag/registry_flags.go Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- pkg/flag/registry_flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index e8bea6e8553a..9334c0886904 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -24,7 +24,7 @@ var ( PasswordStdinFlag = Flag[bool]{ Name: "password-stdin", ConfigName: "registry.password-stdin", - Usage: "password from stdin", + Usage: "password from stdin. Comma-separated passwords are not supported", } RegistryTokenFlag = Flag[string]{ Name: "registry-token", From 5a4f9cb88e711a209fea51a5e889d64b92ca28ab Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 11:53:30 +0400 Subject: [PATCH 13/19] fix: exit when password and password-stdin used together Signed-off-by: knqyf263 --- pkg/flag/registry_flags.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index 9334c0886904..c0c193f88f9a 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -76,6 +76,9 @@ func (f *RegistryFlagGroup) ToOptions() (RegistryOptions, error) { users := f.Username.Value() passwords := f.Password.Value() if f.PasswordStdin.Value() { + if len(passwords) != 0 { + return RegistryOptions{}, xerrors.New("'--password' and '--password-stdin' can't be used at the same time") + } contents, err := io.ReadAll(os.Stdin) if err != nil { return RegistryOptions{}, xerrors.Errorf("failed to read from stdin: %w", err) From 6c44acd3ed50e1d8dcfd170b209b74ae79772376 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 12:06:59 +0400 Subject: [PATCH 14/19] docs: mention --password-stdin doesn't support multiple passwords Signed-off-by: knqyf263 --- docs/docs/advanced/private-registries/index.md | 5 ++++- pkg/flag/registry_flags.go | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/docs/advanced/private-registries/index.md b/docs/docs/advanced/private-registries/index.md index 8b22430bb570..7bac7a2742d5 100644 --- a/docs/docs/advanced/private-registries/index.md +++ b/docs/docs/advanced/private-registries/index.md @@ -51,4 +51,7 @@ In the example above, Trivy attempts to use two pairs of credentials: - USERNAME1/PASSWORD1 - USERNAME2/PASSWORD2 -Please note that the number of usernames and passwords must be the same. \ No newline at end of file +Please note that the number of usernames and passwords must be the same. + +!!! note + `--password-stdin` doesn't support comma-separated passwords. \ No newline at end of file diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index c0c193f88f9a..97757b7c7c75 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -24,7 +24,7 @@ var ( PasswordStdinFlag = Flag[bool]{ Name: "password-stdin", ConfigName: "registry.password-stdin", - Usage: "password from stdin. Comma-separated passwords are not supported", + Usage: "password from stdin. Comma-separated passwords are not supported.", } RegistryTokenFlag = Flag[string]{ Name: "registry-token", @@ -84,10 +84,10 @@ func (f *RegistryFlagGroup) ToOptions() (RegistryOptions, error) { return RegistryOptions{}, xerrors.Errorf("failed to read from stdin: %w", err) } // "--password-stdin" doesn't support comma-separated passwords - passwords = []string{strings.TrimRight(string(contents), "\r\n")} + passwords = strings.Split(strings.TrimRight(string(contents), "\r\n"), ",") } if len(users) != len(passwords) { - return RegistryOptions{}, xerrors.New("the length of usernames and passwords must match") + return RegistryOptions{}, xerrors.New("the number of usernames and passwords must match") } for i, user := range users { credentials = append(credentials, types.Credential{ From d5d1be7365b35a135f484d774c0e416a6cb02eb5 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 12:58:00 +0400 Subject: [PATCH 15/19] docs: auto-generate Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_auth_login.md | 2 +- docs/docs/references/configuration/cli/trivy_config.md | 2 +- docs/docs/references/configuration/cli/trivy_filesystem.md | 2 +- docs/docs/references/configuration/cli/trivy_image.md | 2 +- docs/docs/references/configuration/cli/trivy_kubernetes.md | 2 +- docs/docs/references/configuration/cli/trivy_repository.md | 2 +- docs/docs/references/configuration/cli/trivy_rootfs.md | 2 +- docs/docs/references/configuration/cli/trivy_server.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_auth_login.md b/docs/docs/references/configuration/cli/trivy_auth_login.md index 30e957240f46..8f2cfdb18abc 100644 --- a/docs/docs/references/configuration/cli/trivy_auth_login.md +++ b/docs/docs/references/configuration/cli/trivy_auth_login.md @@ -18,7 +18,7 @@ trivy auth login SERVER [flags] ``` -h, --help help for login --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --username strings username. Comma-separated usernames allowed. ``` diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 6f1d2bf4002e..0c279f1e7bf3 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -39,7 +39,7 @@ trivy config [flags] DIR -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index d6ef984525c0..bbd5257d5f5d 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -68,7 +68,7 @@ trivy filesystem [flags] PATH --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index d3841aaac7a4..779b54f4d5b9 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -86,7 +86,7 @@ trivy image [flags] IMAGE_NAME --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --platform string set platform in the form os/arch if image is multi-platform capable diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index a4921aeeb4a6..6b8058cc00f0 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -83,7 +83,7 @@ trivy kubernetes [flags] [CONTEXT] --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --qps float specify the maximum QPS to the master from this client (default 5) diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 60f13d1462b3..190640f5cb2a 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -68,7 +68,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 1e0a42137a6d..2f37484d0328 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -70,7 +70,7 @@ trivy rootfs [flags] ROOTDIR --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_server.md b/docs/docs/references/configuration/cli/trivy_server.md index f156d266c4b1..80eacd43ee4f 100644 --- a/docs/docs/references/configuration/cli/trivy_server.md +++ b/docs/docs/references/configuration/cli/trivy_server.md @@ -30,7 +30,7 @@ trivy server [flags] --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --password-stdin password from stdin + --password-stdin password from stdin. Comma-separated passwords are not supported. --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend From b5be50fa81ae9d88573270a75cd17b8caf366944 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 12:58:13 +0400 Subject: [PATCH 16/19] feat: validate the credential Signed-off-by: knqyf263 --- pkg/commands/auth/run.go | 13 +++++++++++- pkg/commands/auth/run_test.go | 37 ++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go index 40e793540f25..4538bf9f42b1 100644 --- a/pkg/commands/auth/run.go +++ b/pkg/commands/auth/run.go @@ -8,13 +8,15 @@ import ( "github.com/docker/cli/cli/config/types" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/flag" "github.com/aquasecurity/trivy/pkg/log" ) -func Login(_ context.Context, registry string, opts flag.Options) error { +func Login(ctx context.Context, registry string, opts flag.Options) error { if len(opts.Credentials) == 0 { return xerrors.New("username and password required") } else if len(opts.Credentials) > 1 { @@ -27,6 +29,15 @@ func Login(_ context.Context, registry string, opts flag.Options) error { } serverAddress := reg.Name() + // Validate the credential + _, err = transport.NewWithContext(ctx, reg, &authn.Basic{ + Username: opts.Credentials[0].Username, + Password: opts.Credentials[0].Password, + }, remote.DefaultTransport, []string{transport.PullScope}) + if err != nil { + return xerrors.Errorf("failed to authenticate: %w", err) + } + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) if err != nil { return xerrors.Errorf("failed to load docker config: %w", err) diff --git a/pkg/commands/auth/run_test.go b/pkg/commands/auth/run_test.go index d3dfb5b80c56..2b2df244031f 100644 --- a/pkg/commands/auth/run_test.go +++ b/pkg/commands/auth/run_test.go @@ -2,11 +2,16 @@ package auth_test import ( "context" + "os" "path/filepath" + "strings" "testing" + "github.com/samber/lo" "github.com/stretchr/testify/require" + testauth "github.com/aquasecurity/testdocker/auth" + "github.com/aquasecurity/testdocker/registry" "github.com/aquasecurity/trivy/pkg/commands/auth" "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/flag" @@ -25,7 +30,6 @@ func TestLogin(t *testing.T) { { name: "single credential", args: args{ - registry: "auth.test", opts: flag.Options{ RegistryOptions: flag.RegistryOptions{ Credentials: []types.Credential{ @@ -41,7 +45,6 @@ func TestLogin(t *testing.T) { { name: "multiple credentials", args: args{ - registry: "auth.test", opts: flag.Options{ RegistryOptions: flag.RegistryOptions{ Credentials: []types.Credential{ @@ -85,13 +88,22 @@ func TestLogin(t *testing.T) { wantErr: "registries must be valid RFC 3986 URI authorities", }, } + + tr := registry.NewDockerRegistry(registry.Option{ + Auth: testauth.Auth{ + User: "user", + Password: "pass", + }, + }) + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set the DOCKER_CONFIG environment variable to a temporary directory // so that the test does not interfere with the user's configuration. t.Setenv("DOCKER_CONFIG", filepath.Join(t.TempDir(), "config.json")) - err := auth.Login(context.Background(), tt.args.registry, tt.args.opts) + reg := lo.Ternary(tt.args.registry == "", strings.TrimPrefix(tr.URL, "http://"), tt.args.registry) + err := auth.Login(context.Background(), reg, tt.args.opts) if tt.wantErr != "" { require.ErrorContains(t, err, tt.wantErr) return @@ -104,22 +116,19 @@ func TestLogin(t *testing.T) { func TestLogout(t *testing.T) { // Set the DOCKER_CONFIG environment variable to a temporary directory // so that the test does not interfere with the user's configuration. - t.Setenv("DOCKER_CONFIG", t.TempDir()) + tmpDir := t.TempDir() + t.Setenv("DOCKER_CONFIG", tmpDir) t.Run("success", func(t *testing.T) { - err := auth.Login(context.Background(), "auth.test", flag.Options{ - RegistryOptions: flag.RegistryOptions{ - Credentials: []types.Credential{ - { - Username: "user", - Password: "pass", - }, - }, - }, - }) + configFile := filepath.Join(tmpDir, "config.json") + err := os.WriteFile(configFile, []byte(`{"auths": {"auth.test": {"auth": "dXNlcjpwYXNz"}}}`), 0600) require.NoError(t, err) + err = auth.Logout(context.Background(), "auth.test") require.NoError(t, err) + b, err := os.ReadFile(configFile) + require.NoError(t, err) + require.JSONEq(t, `{"auths": {}}`, string(b)) }) t.Run("not found", func(t *testing.T) { err := auth.Logout(context.Background(), "notfound.test") From d138cdf67ab96a12262bc23c1f2eb3b13886ff66 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 13:41:33 +0400 Subject: [PATCH 17/19] feat: support insecure flag Signed-off-by: knqyf263 --- integration/registry_test.go | 1 + pkg/commands/auth/run.go | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/integration/registry_test.go b/integration/registry_test.go index 7b5d02db3a6b..ce77db5ad74a 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -301,6 +301,7 @@ func setupEnv(t *testing.T, imageRef name.Reference, baseDir string, opt registr opt.Username, "--password", opt.Password, + "--insecure", imageRef.Context().RegistryStr(), }) if err != nil { diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go index 4538bf9f42b1..7659702f2b7e 100644 --- a/pkg/commands/auth/run.go +++ b/pkg/commands/auth/run.go @@ -2,6 +2,7 @@ package auth import ( "context" + "net/http" "os" "github.com/docker/cli/cli/config" @@ -23,7 +24,7 @@ func Login(ctx context.Context, registry string, opts flag.Options) error { return xerrors.New("multiple credentials are not allowed") } - reg, err := name.NewRegistry(registry) + reg, err := parseRegistry(registry, opts) if err != nil { return xerrors.Errorf("failed to parse registry: %w", err) } @@ -33,7 +34,7 @@ func Login(ctx context.Context, registry string, opts flag.Options) error { _, err = transport.NewWithContext(ctx, reg, &authn.Basic{ Username: opts.Credentials[0].Username, Password: opts.Credentials[0].Password, - }, remote.DefaultTransport, []string{transport.PullScope}) + }, httpTransport(opts), []string{reg.Scope(transport.PullScope)}) if err != nil { return xerrors.Errorf("failed to authenticate: %w", err) } @@ -57,12 +58,12 @@ func Login(ctx context.Context, registry string, opts flag.Options) error { if err := cf.Save(); err != nil { return xerrors.Errorf("failed to save docker config: %w", err) } - log.Info("Logged in", log.FilePath(cf.Filename), log.String("username", opts.Credentials[0].Username)) + log.Info("Login succeeded", log.FilePath(cf.Filename), log.String("username", opts.Credentials[0].Username)) return nil } func Logout(_ context.Context, registry string) error { - reg, err := name.NewRegistry(registry) + reg, err := parseRegistry(registry, flag.Options{}) if err != nil { return xerrors.Errorf("failed to parse registry: %w", err) } @@ -86,3 +87,23 @@ func Logout(_ context.Context, registry string) error { log.Info("Logged out", log.FilePath(cf.Filename)) return nil } + +func parseRegistry(registry string, opts flag.Options) (name.Registry, error) { + var nameOpts []name.Option + if opts.Insecure { + nameOpts = append(nameOpts, name.Insecure) + } + reg, err := name.NewRegistry(registry, nameOpts...) + if err != nil { + return name.Registry{}, xerrors.Errorf("failed to parse registry: %w", err) + } + return reg, nil +} + +func httpTransport(opts flag.Options) *http.Transport { + tr := remote.DefaultTransport.(*http.Transport).Clone() + if opts.Insecure { + tr.TLSClientConfig.InsecureSkipVerify = true + } + return tr +} From 85d0b67265dab2d37102900308ceb2874cd6bae2 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 8 Oct 2024 15:32:55 +0400 Subject: [PATCH 18/19] revert: split passwords from stdin Signed-off-by: knqyf263 --- pkg/flag/registry_flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index 97757b7c7c75..9c03a07b8872 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -84,7 +84,7 @@ func (f *RegistryFlagGroup) ToOptions() (RegistryOptions, error) { return RegistryOptions{}, xerrors.Errorf("failed to read from stdin: %w", err) } // "--password-stdin" doesn't support comma-separated passwords - passwords = strings.Split(strings.TrimRight(string(contents), "\r\n"), ",") + passwords = []string{strings.TrimRight(string(contents), "\r\n")} } if len(users) != len(passwords) { return RegistryOptions{}, xerrors.New("the number of usernames and passwords must match") From 2b4b54f5c323c0e3fa3e2991864170c61a6d1fa7 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 9 Oct 2024 14:10:30 +0400 Subject: [PATCH 19/19] docs: auto-generate Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_sbom.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 4eaedcf17aa5..55df0959deb6 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -48,6 +48,7 @@ trivy sbom [flags] SBOM_PATH -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend