mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 23:26:39 -08:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
```
|
||||||
@@ -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,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user