anchore / grype

A vulnerability scanner for container images and filesystems
Apache License 2.0
8.86k stars 574 forks source link

Grype only supports SKOPEO when using 'docker-archive' format. #2051

Open SDDunt opened 3 months ago

SDDunt commented 3 months ago

What happened: Since the documentation: https://github.com/anchore/grype#supported-sources says: "or skopeo copy commands)" I tried to scan backup copies of our docker images and grype does not seem to scan the directories.. It reports NO package, NO executable and NO vulnerabilities:

To simplify I used an off the shelf busybox image:

./skopeo --version                                                    
skopeo version 1.17.0-dev commit: d2357b38fa17d36b6fdb3a96e8e7b07c7cc7490a                               

$ ./skopeo copy docker://busybox:latest dir:/tmp/busybox            
Getting image source signatures                                                                          
Copying blob ec562eabd705 done   |                                                                       
Copying config 65ad0d468e done   |                                                                       
Writing manifest to image destination                                                                    
$ ll /tmp/busybox/                                                      

-rw-r--r--  1 sdunt sdunt     372 Aug 12 13:19 65ad0d468eb1c558bf7f4e64e790f586e9eda649ee9f130cd0e835b292bbc5ac
-rw-r--r--  1 sdunt sdunt 2152663 Aug 12 13:19 ec562eabd705d25bfea8c8d79e4610775e375524af00552fe871d3338261563c
-rw-r--r--  1 sdunt sdunt     610 Aug 12 13:19 manifest.json                                             
-rw-r--r--  1 sdunt sdunt      33 Aug 12 13:19 version                                                   

When I scan that, grype does NOT find any packages or any issues:

$ grype dir:/tmp/busybox
 ✔ Vulnerability DB                [no update available]  
 ✔ Indexed file system                                                                                                                                              /tmp/busybox
 ✔ Cataloged contents                                                                      8dcf2e54f2bb378c9945f36f61a2499ef66113889d4f111bebab99b582917c85
   ├── ✔ Packages                        [0 packages]  
   └── ✔ Executables                     [0 executables]  
 ✔ Scanned for vulnerabilities     [0 vulnerability matches]  
   ├── by severity: 0 critical, 0 high, 0 medium, 0 low, 0 negligible
   └── by status:   0 fixed, 0 not-fixed, 0 ignored 
[0000]  WARN no explicit name and version provided for directory source, deriving artifact ID from the given path (which is not ideal)
No vulnerabilities found

IF I use skopeo and export as a 'docker-archive:

$  ./skopeo copy docker://busybox:latest docker-archive:/tmp/busybox.tar

THEN I can scan it:

 grype /tmp/busybox.tar
 ✔ Vulnerability DB                [no update available]  
 ✔ Parsed image                                                                                                                           sha256:65ad0d468eb1c558bf7f4e64e790f586e9eda649ee9f130cd0e835b292bbc5ac
 ✔ Cataloged contents                                                                                                                            402d7c3775962fa983002c5f1ce8f514eec8e463dcc601a7235f06dbebb42a43
   ├── ✔ Packages                        [1 packages]  
   └── ✔ Executables                     [11 executables]  
 ✔ Scanned for vulnerabilities     [0 vulnerability matches]  
   ├── by severity: 0 critical, 0 high, 4 medium, 0 low, 0 negligible
   └── by status:   0 fixed, 4 not-fixed, 0 ignored 
NAME     INSTALLED  FIXED-IN  TYPE    VULNERABILITY   SEVERITY 
busybox  1.36.1               binary  CVE-2023-42366  Medium    
busybox  1.36.1               binary  CVE-2023-42365  Medium    
busybox  1.36.1               binary  CVE-2023-42364  Medium    
busybox  1.36.1               binary  CVE-2023-42363  Medium

Either your docs need to be more explicit.. Or I'd prefer that grype also supposed the dir: version of the skopeo copy command.

What you expected to happen: When I scan the same image directly from docker I get packages, and executables, and vulnerabilities ..

$ grype busybox
 ✔ Vulnerability DB                [updated]  
 ✔ Loaded image                                                                                                                                                                                    busybox:latest
 ✔ Parsed image                                                                                                                           sha256:65ad0d468eb1c558bf7f4e64e790f586e9eda649ee9f130cd0e835b292bbc5ac
 ✔ Cataloged contents                                                                                                                            402d7c3775962fa983002c5f1ce8f514eec8e463dcc601a7235f06dbebb42a43
   ├── ✔ Packages                        [1 packages]  
   └── ✔ Executables                     [11 executables]  
 ✔ Scanned for vulnerabilities     [0 vulnerability matches]  
   ├── by severity: 0 critical, 0 high, 4 medium, 0 low, 0 negligible
   └── by status:   0 fixed, 4 not-fixed, 0 ignored 
NAME     INSTALLED  FIXED-IN  TYPE    VULNERABILITY   SEVERITY 
busybox  1.36.1               binary  CVE-2023-42366  Medium    
busybox  1.36.1               binary  CVE-2023-42365  Medium    
busybox  1.36.1               binary  CVE-2023-42364  Medium    
busybox  1.36.1               binary  CVE-2023-42363  Medium

How to reproduce it (as minimally and precisely as possible):

See steps above.

Please also include the grype command and any configuration used.

No grype config changes made after I installed it via:

curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

Environment: Ubuntu 22.04, on intel - amd64

willmurphyscode commented 3 months ago

Hi @SDDunt,

Thanks for the issue and the detailed steps to reproduce.

The docs specifically say that they support image archives as a result of skopeo copy:

# scan a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
grype path/to/image.tar

We also support scanning a directory.

However, if you look at the result of copying a docker image to a directory via skopeo, skopeo has just unpacked the OCI format, rather than inflated the filesystem:

$ skopeo copy --override-os linux --override-arch amd64 docker://busybox:latest dir:/tmp/busybox
$ tree /tmp/busybox
/tmp/busybox
├── 65ad0d468eb1c558bf7f4e64e790f586e9eda649ee9f130cd0e835b292bbc5ac
├── ec562eabd705d25bfea8c8d79e4610775e375524af00552fe871d3338261563c
├── manifest.json
└── version

As you can see, there aren't any packages or anything in that directory, just OCI image internals. Syft and Grype, when scanning a directory, are not expecting an untarred OCI image and so don't find anything.

If you want to scan archived images with Syft or Grype, please use docker save or skopeo copy ... docker-archive:... to make a .tar from the OCI image; Syft and Grype both support scanning that.

Is there a specific use case you had in mind? I am not sure of a reason it would be preferable to skopeo copy to a directory rather than a docker archive, but maybe I'm missing something.

SDDunt commented 3 months ago

Thanks for the explanation. We have no particular reason for using skopeo copy (without the docker-archive). We just got started that way. We're changing our process to use the docker-archive so we can run grype against the backup copies.

(we are trying to reduce how many times we are pulling data out of AWS and S3)

Is it possible that the docs be updated to specify skopeo copy ... docker-archive:... so it is clear that the docker-archive option is needed?

wagoodman commented 2 months ago

We do support OCI dir layouts out of the box too:

grype oci-dir:path/to/dir

Ideally we should make an update where grype path/to/dir will automatically figure if this is dir: vs oci-dir:

willmurphyscode commented 2 weeks ago

Marking as ready and adding some notes. There are 2 changes we want to make:

  1. Make a nice docs area that lists all the formats grype accepts and how to specify them.
  2. Make it so that Grype when invoked with a source that doesn't specify a format (e.g. grype some/path as opposed to grype dir:some/path) Grype detects an OCI dir layout automatically.