feat(image): customer podman host or socket option (#6256)

Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
This commit is contained in:
Parvez
2024-03-11 09:57:57 +05:30
committed by GitHub
parent 2a9d9bd214
commit 9d2057a7c2
10 changed files with 77 additions and 7 deletions

View File

@@ -78,6 +78,7 @@ trivy image [flags] IMAGE_NAME
--parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --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 strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons.
--platform string set platform in the form os/arch if image is multi-platform capable --platform string set platform in the form os/arch if image is multi-platform capable
--podman-host string unix podman socket path to use for podman scanning
--policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0") --policy-bundle-repository string OCI registry URL to retrieve policy bundle from (default "ghcr.io/aquasecurity/trivy-policies:0")
--policy-namespaces strings Rego namespaces --policy-namespaces strings Rego namespaces
--redis-ca string redis ca file location, if using redis as cache backend --redis-ca string redis ca file location, if using redis as cache backend

View File

@@ -203,6 +203,11 @@ image:
# Same as '--docker-host' # Same as '--docker-host'
# Default is empty # Default is empty
host: host:
podman:
# Same as '--podman-host'
# Default is empty
host:
``` ```
## Vulnerability Options ## Vulnerability Options

View File

@@ -500,3 +500,10 @@ You can configure Docker daemon socket with `DOCKER_HOST` or `--docker-host`.
```shell ```shell
$ trivy image --docker-host tcp://127.0.0.1:2375 YOUR_IMAGE $ trivy image --docker-host tcp://127.0.0.1:2375 YOUR_IMAGE
``` ```
### Configure Podman daemon socket to connect to.
You can configure Podman daemon socket with `--podman-host`.
```shell
$ trivy image --podman-host /run/user/1000/podman/podman.sock YOUR_IMAGE
```

View File

@@ -670,6 +670,9 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
DockerOptions: ftypes.DockerOptions{ DockerOptions: ftypes.DockerOptions{
Host: opts.DockerHost, Host: opts.DockerHost,
}, },
PodmanOptions: ftypes.PodmanOptions{
Host: opts.PodmanHost,
},
ImageSources: opts.ImageSources, ImageSources: opts.ImageSources,
}, },

View File

@@ -21,8 +21,8 @@ func tryDockerDaemon(_ context.Context, imageName string, ref name.Reference, op
} }
func tryPodmanDaemon(_ context.Context, imageName string, _ name.Reference, _ types.ImageOptions) (types.Image, func(), error) { func tryPodmanDaemon(_ context.Context, imageName string, _ name.Reference, opts types.ImageOptions) (types.Image, func(), error) {
img, cleanup, err := daemon.PodmanImage(imageName) img, cleanup, err := daemon.PodmanImage(imageName, opts.PodmanOptions.Host)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -115,6 +115,46 @@ func Test_image_ConfigNameWithCustomDockerHost(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
} }
func Test_image_ConfigNameWithCustomPodmanHost(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("podman.sock is not available for Windows CI")
}
ref, err := name.ParseReference("alpine:3.11")
require.NoError(t, err)
eo := engine.Option{
APIVersion: opt.APIVersion,
ImagePaths: map[string]string{
"index.docker.io/library/alpine:3.11": "../../test/testdata/alpine-311.tar.gz",
},
}
runtimeDir, err := os.MkdirTemp("", "daemon")
require.NoError(t, err)
dir := filepath.Join(runtimeDir, "image")
err = os.MkdirAll(dir, os.ModePerm)
require.NoError(t, err)
podmanSocket := filepath.Join(dir, "image-test-podman-socket.sock")
eo.UnixDomainSocket = podmanSocket
te := engine.NewDockerEngine(eo)
defer te.Close()
img, cleanup, err := PodmanImage(ref.Name(), podmanSocket)
require.NoError(t, err)
defer cleanup()
conf, err := img.ConfigName()
assert.Equal(t, v1.Hash{
Algorithm: "sha256",
Hex: "a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
}, conf)
assert.Nil(t, err)
}
func Test_image_ConfigFile(t *testing.T) { func Test_image_ConfigFile(t *testing.T) {
tests := []struct { tests := []struct {
name string name string

View File

@@ -25,10 +25,13 @@ type podmanClient struct {
c http.Client c http.Client
} }
func newPodmanClient() (podmanClient, error) { func newPodmanClient(host string) (podmanClient, error) {
// Get Podman socket location // Get Podman socket location
sockDir := os.Getenv("XDG_RUNTIME_DIR") sockDir := os.Getenv("XDG_RUNTIME_DIR")
socket := filepath.Join(sockDir, "podman", "podman.sock") socket := filepath.Join(sockDir, "podman", "podman.sock")
if host != "" {
socket = host
}
if _, err := os.Stat(socket); err != nil { if _, err := os.Stat(socket); err != nil {
return podmanClient{}, xerrors.Errorf("no podman socket found: %w", err) return podmanClient{}, xerrors.Errorf("no podman socket found: %w", err)
@@ -109,10 +112,10 @@ func (p podmanClient) imageSave(_ context.Context, imageNames []string) (io.Read
// PodmanImage implements v1.Image by extending daemon.Image. // PodmanImage implements v1.Image by extending daemon.Image.
// The caller must call cleanup() to remove a temporary file. // The caller must call cleanup() to remove a temporary file.
func PodmanImage(ref string) (Image, func(), error) { func PodmanImage(ref, host string) (Image, func(), error) {
cleanup := func() {} cleanup := func() {}
c, err := newPodmanClient() c, err := newPodmanClient(host)
if err != nil { if err != nil {
return nil, cleanup, xerrors.Errorf("unable to initialize Podman client: %w", err) return nil, cleanup, xerrors.Errorf("unable to initialize Podman client: %w", err)
} }

View File

@@ -84,7 +84,7 @@ func TestPodmanImage(t *testing.T) {
ref, err := name.ParseReference(tt.imageName) ref, err := name.ParseReference(tt.imageName)
require.NoError(t, err) require.NoError(t, err)
img, cleanup, err := PodmanImage(ref.Name()) img, cleanup, err := PodmanImage(ref.Name(), "")
defer cleanup() defer cleanup()
if tt.wantErr { if tt.wantErr {

View File

@@ -60,7 +60,7 @@ type DockerOptions struct {
} }
type PodmanOptions struct { type PodmanOptions struct {
// Add Podman-specific options Host string
} }
type ContainerdOptions struct { type ContainerdOptions struct {

View File

@@ -45,6 +45,12 @@ var (
Default: "", Default: "",
Usage: "unix domain socket path to use for docker scanning", Usage: "unix domain socket path to use for docker scanning",
} }
PodmanHostFlag = Flag[string]{
Name: "podman-host",
ConfigName: "image.podman.host",
Default: "",
Usage: "unix podman socket path to use for podman scanning",
}
SourceFlag = Flag[[]string]{ SourceFlag = Flag[[]string]{
Name: "image-src", Name: "image-src",
ConfigName: "image.source", ConfigName: "image.source",
@@ -60,6 +66,7 @@ type ImageFlagGroup struct {
ScanRemovedPkgs *Flag[bool] ScanRemovedPkgs *Flag[bool]
Platform *Flag[string] Platform *Flag[string]
DockerHost *Flag[string] DockerHost *Flag[string]
PodmanHost *Flag[string]
ImageSources *Flag[[]string] ImageSources *Flag[[]string]
} }
@@ -69,6 +76,7 @@ type ImageOptions struct {
ScanRemovedPkgs bool ScanRemovedPkgs bool
Platform ftypes.Platform Platform ftypes.Platform
DockerHost string DockerHost string
PodmanHost string
ImageSources ftypes.ImageSources ImageSources ftypes.ImageSources
} }
@@ -79,6 +87,7 @@ func NewImageFlagGroup() *ImageFlagGroup {
ScanRemovedPkgs: ScanRemovedPkgsFlag.Clone(), ScanRemovedPkgs: ScanRemovedPkgsFlag.Clone(),
Platform: PlatformFlag.Clone(), Platform: PlatformFlag.Clone(),
DockerHost: DockerHostFlag.Clone(), DockerHost: DockerHostFlag.Clone(),
PodmanHost: PodmanHostFlag.Clone(),
ImageSources: SourceFlag.Clone(), ImageSources: SourceFlag.Clone(),
} }
} }
@@ -94,6 +103,7 @@ func (f *ImageFlagGroup) Flags() []Flagger {
f.ScanRemovedPkgs, f.ScanRemovedPkgs,
f.Platform, f.Platform,
f.DockerHost, f.DockerHost,
f.PodmanHost,
f.ImageSources, f.ImageSources,
} }
} }
@@ -121,6 +131,7 @@ func (f *ImageFlagGroup) ToOptions() (ImageOptions, error) {
ScanRemovedPkgs: f.ScanRemovedPkgs.Value(), ScanRemovedPkgs: f.ScanRemovedPkgs.Value(),
Platform: platform, Platform: platform,
DockerHost: f.DockerHost.Value(), DockerHost: f.DockerHost.Value(),
PodmanHost: f.PodmanHost.Value(),
ImageSources: xstrings.ToTSlice[ftypes.ImageSource](f.ImageSources.Value()), ImageSources: xstrings.ToTSlice[ftypes.ImageSource](f.ImageSources.Value()),
}, nil }, nil
} }